Hello Bill,

Yes ... your right. The problem is not with J but with the ADODB choking with 
data (this thing runs on J504).

You see, the way I use ADO is to submit a bunch of SQL statements wrapped with 
a "BEGIN TRANS". The problem with this is that all of the tables are related 
and there are triggers firing on every update and inserts. So ADO either times 
out and quits or just plain throws an error.

I was able to work around this by NOT using transactions and by doing batch 
insert/updates of data by 512 rows. :) Btw, 512 was not arbitrary ... I 
actually did a lot of server response test (I don’t remember the details 
anymore) by cutting data by a progression of 8's. So 512 was the biggest number 
of rows in one block that wouldn't bring an OLTP MS-SQL server to its knees. It 
works but I felt that it wasn't really "safe".

So with the latest version using J601 ... we actually removed all MS-SQL 
interaction and I've created a some C# functions which would read a .NET 
DataSet or Table and save it into a J variable. Here is one of them:

        /// <summary>
        /// Converts data to a multidimensional array that can be imported by 
EOE
        /// </summary>
        public static void dataTableToEOE(DataTable sourceTable, out object 
outFields, out object outData)
        {
            // Variable declaration 
            int cols = sourceTable.Columns.Count;
            object[,] fields = new object[cols, 2];
            int rows = sourceTable.Rows.Count;
            object[,] data = new object[rows, cols];
            int icol = 0;
            int irow = 0;
            string oType;
            string strDateTime;
            DateTime dtDateTime;

            // Lets create the fieldlist first
            foreach (DataColumn myDataColumn in sourceTable.Columns)
            {
                // Save the field name
                fields[icol, 0] = myDataColumn.ColumnName.ToString();
                oType = myDataColumn.DataType.ToString();
                switch (oType)
                {
                    case "System.Byte":
                    case "System.Decimal":
                    case "System.Double":
                    case "System.Int16":
                    case "System.Int32":
                    case "System.Int64":
                    case "System.SByte":
                    case "System.UInt16":
                    case "System.UInt32":
                    case "System.UInt64":
                        fields[icol, 1] = "numeric";
                        break;
                    case "System.DateTime":
                    case "System.TimeSpan":
                        fields[icol, 1] = "datetime";
                        break;
                    case "System.Boolean":
                        fields[icol, 1] = "boolean";
                        break;
                    default:
                        // Treat everyting else as string
                        fields[icol, 1] = "text";
                        break;
                }
                // Increment counter
                icol++;
            }

            // Now retrieve all row data
            foreach (DataRow myDataRow in sourceTable.Rows)
            {
                // Get the value for each of the data
                for (int i = 0; i < myDataRow.ItemArray.Length; i++)
                {
                    oType = fields[i, 1].ToString();
                    switch (oType)
                    {
                        case "numeric":
                            if (myDataRow[i] == DBNull.Value)
                            {
                                data[irow, i] = 0;
                            }
                            else
                            {
                                data[irow, i] = Convert.ToDouble(myDataRow[i]);
                            }
                            break;
                        case "datetime":
                            if (myDataRow[i] == DBNull.Value)
                            {
                                data[irow, i] = "";
                            }
                            else
                            {
                                //data[irow, i] = 
Convert.ToDateTime(myDataRow[i]).ToString("MM/dd/yyyy HH:mm:ss");
                                dtDateTime = (DateTime)myDataRow[i];
                                strDateTime = dtDateTime.Month.ToString() + "/" 
+ dtDateTime.Day.ToString() + "/";
                                strDateTime += dtDateTime.Year.ToString() + " " 
+ dtDateTime.Hour.ToString();
                                strDateTime += ":" + 
dtDateTime.Minute.ToString() + ":" + dtDateTime.Second.ToString();
                                data[irow, i] = strDateTime;
                            }
                            break;
                        case "boolean":
                            if (myDataRow[i] == DBNull.Value)
                            {
                                data[irow, i] = 0;
                            }
                            else
                            {
                                data[irow, i] = Convert.ToByte(myDataRow[i]);
                            }
                            break;
                        case "text":
                            if (myDataRow[i] == DBNull.Value)
                            {
                                data[irow, i] = "";
                            }
                            else
                            {
                                data[irow, i] = myDataRow[i];
                            }
                            break;
                    }
                }

                //increment row counter
                irow++;
            }

            // save and return the data
            outFields = fields;
            outData = data;
        }

What you'll get from the C# code above are 2 arrays, the list of fieldnames and 
corresponding datatype and the actual SQL data in a two dimensional matrix. 

Here are some actual codes in my project (I'm way too lazy to make a new one):
IN C#:
                // STEP 1: Get the size information
                sqlCommand = "USE " + this.DatabaseServer + @"
SELECT     SIZE_CODE, SIZE_SCHEMA_CODE, SIZE_CODE_DESC, SIZE_SEQ_NO
FROM         dbo.ZIO_SIZES
WHERE     (IO_Number = '" + ioNumber + "')";
                DataTable dtZIOH = (DataTable)this.executeSQL(sqlCommand);
                // STEP 2: Send this data to EOE
                object outFields, outData;
                dataTableToEOE(sourceTable, out outFields, out outData);
                jObject.SetB("SIZES_FIELDS", ref outFields)
                jObject.SetB("SIZES_DATA", ref outData)

So in your J Session, you can now see your data like so:
   SIZES_FIELDS
+----------------+-------+
|Size_Code       |text   |
+----------------+-------+
|Size_Schema_code|text   |
+----------------+-------+
|Size_Code_Desc  |text   |
+----------------+-------+
|Size_Seq_No     |numeric|
+----------------+-------+
   SIZES_DATA
+--+----+-----------+-+
|S |M001|Small      |1|
+--+----+-----------+-+
|M |M001|Medium     |2|
+--+----+-----------+-+
|L |M001|Large      |3|
+--+----+-----------+-+
|XL|M001|Extra Large|4|
+--+----+-----------+-+
   NB. Pretty print
   SIZES_DATA,~ {. "1 SIZES_FIELDS
+---------+----------------+--------------+-----------+
|Size_Code|Size_Schema_code|Size_Code_Desc|Size_Seq_No|
+---------+----------------+--------------+-----------+
|S        |M001            |Small         |1          |
+---------+----------------+--------------+-----------+
|M        |M001            |Medium        |2          |
+---------+----------------+--------------+-----------+
|L        |M001            |Large         |3          |
+---------+----------------+--------------+-----------+
|XL       |M001            |Extra Large   |4          |
+---------+----------------+--------------+-----------+
   NB. Check if we have the correct data types
   SIZES_FIELDS,. |: datatype each SIZES_DATA
+----------------+-------+--------+--------+--------+--------+
|Size_Code       |text   |literal |literal |literal |literal |
+----------------+-------+--------+--------+--------+--------+
|Size_Schema_code|text   |literal |literal |literal |literal |
+----------------+-------+--------+--------+--------+--------+
|Size_Code_Desc  |text   |literal |literal |literal |literal |
+----------------+-------+--------+--------+--------+--------+
|Size_Seq_No     |numeric|floating|floating|floating|floating|
+----------------+-------+--------+--------+--------+--------+

It works! I'm happy. :)

r/Alex

P.S.
I've been meaning to post something like this to the WIKI for sometime now ... 
hehehe ... I'm just way too lazy. :P

-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of bill lam
Sent: Thursday, January 03, 2008 11:50 PM
To: General forum
Subject: Re: [Jgeneral] Successful stories

Alex Rufon wrote:
> 6. The slowest part of the system is not during J calculation but during the 
> time J calls ADO to retrieve and write to MS-SQL. We've proven this with the 
> new version where J does not connect directly to the DB and instead expect 
> array input and output.

I'm not familiar with ADODB, does ADODB has the capacity to do column binding 
(not sure ado use this term) ? And IMO the bottleneck is not J interfacing sql 
database, but wd oleautomaion interfacing com or dotnet is the real bottleneck. 
My experience is that J can insert 10000 rows into sql database within a few 
seconds.

----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to