示例#1
0
        public virtual void Start()
        {
#if CODECONTRACTS
            Contract.Requires <InvalidOperationException>(
                !string.IsNullOrWhiteSpace(Table) || !string.IsNullOrWhiteSpace(QueryInternal),
                "Table and Query properties are null.");
#else
            if (string.IsNullOrWhiteSpace(Table) && string.IsNullOrWhiteSpace(QueryInternal))
            {
                throw new InvalidOperationException("Table and Query properties are null.");
            }
#endif

            // PQexec does not set field types in PQresult for COPY FROM statements,
            // just retrieve 0 rows for the field types of Table or Query

            // TODO use PqsqlCopyColumnsCollection for ColumnList
            StringBuilder sb = new StringBuilder();
            if (!SuppressSchemaQueryInternal)
            {
                if (QueryInternal == null)
                {
                    sb.AppendFormat("SELECT {0} FROM {1} LIMIT 0;", (object)ColumnList ?? '*', Table);
                }
                else
                {
                    sb.AppendFormat("{0} LIMIT 0;", QueryInternal);
                }

                // fetch number of columns and store column information
                using (PqsqlCommand cmd = new PqsqlCommand(mConn))
                {
                    cmd.CommandText    = sb.ToString();
                    cmd.CommandType    = CommandType.Text;
                    cmd.CommandTimeout = CopyTimeout;

                    using (PqsqlDataReader r = cmd.ExecuteReader(CommandBehavior.Default))
                    {
                        // just pick current row information
                        PqsqlColInfo[] src = r.RowInformation;

                        if (src == null)
                        {
                            throw new PqsqlException("Cannot retrieve RowInformation for '" +
                                                     QueryInternal ?? Table + "'.");
                        }

                        mColumns = src.Length;
                        mRowInfo = new PqsqlColInfo[mColumns];

                        Array.Copy(src, mRowInfo, mColumns);
                    }
                }

                sb.Clear();
            }

            // now build COPY FROM statement
            sb.Append("COPY ");

            if (QueryInternal == null)
            {
                sb.AppendFormat("{0} ", Table);

                // always create list of columns if not SuppressSchemaQuery
                if (string.IsNullOrEmpty(ColumnList))
                {
                    if (!SuppressSchemaQueryInternal)
                    {
                        // just assume that we use standard table order
                        sb.AppendFormat("({0})", string.Join(",", mRowInfo.Select(r => r.ColumnName)));
                    }
                }
                else
                {
                    // let user decide the column order
                    sb.AppendFormat("({0})", ColumnList);
                }
            }
            else
            {
                sb.AppendFormat("({0})", QueryInternal);
            }

            sb.AppendFormat(" {0} BINARY", CopyStmtDirection);

            byte[] q = PqsqlUTF8Statement.CreateUTF8Statement(sb);

            IntPtr         res;
            ExecStatusType s = mConn.Exec(q, out res);

            // result buffer should contain column information and PGconn should be in COPY_IN state
            if (res == IntPtr.Zero || s != QueryResultType)
            {
                mConn.Consume(res);                 // we might receive several results...
                throw new PqsqlException("Could not execute statement «" + sb + "»: " + mConn.GetErrorMessage());
            }

            // check first column format, current implementation will have all columns set to binary
            if (PqsqlWrapper.PQfformat(res, 0) == 0)
            {
                mConn.Consume(res);
                throw new PqsqlException("PqsqlCopyFrom only supports BINARY format.");
            }

            var nFields = PqsqlWrapper.PQnfields(res);
            if (SuppressSchemaQueryInternal)
            {
                mColumns = nFields;
            }
            else
            {
                // sanity check
                if (mColumns != nFields)
                {
                    mConn.Consume(res);
                    throw new PqsqlException("Received wrong number of columns for " + sb);
                }
            }

            // done with result inspection
            PqsqlWrapper.PQclear(res);
        }