Hypothetically speaking, the J datastructure which best
matches a .Net DataTable would be an N,3 array of
boxes where N is the number of columns.

The three boxes which would describe a column are:

0 { The name of the column.

1 { A boolean list with 1 for non-null and 0 for null values.
This can be a scalar 1 for columns which do not allow nulls.

2 { A list containing the elements within that column
(using fill elements for null values).

Playing around with SetB/GetB, it looks like they do not deal
with nested arrays.  However for many cases you can treat
a data table as N*3 flat arrays, instead.

Alternatively, you can supply a literal value to SetB and convert
that to a boxed array using 3!:2.  I'm going to attempt to attach
to this message an example of how you might put a DataTable
into this format.

The value produced by the GetBytes() method of the JConvert
class is suitable as the second argument for j.SetB(,) and
is intended to be an argument to 3!:2 within the J session.

That said, this is alpha quality software.  It seems to work for
me, but I've not tested all code paths.  Also, when I display
the array, it looks funny inside J, so I suspect I messed
something up -- something which J does not treat as an
error case but nevertheless assumes something different... or
maybe I'm just worrying about nothing.

FYI,

--
Raul
using System;
using System.Data;
using System.Collections.Generic;
using System.Runtime;
using System.Text;

namespace JSoftware {
    public class JConvert {
        private byte[] _bytes;
        private int _siz;
        private int _total;
        private int _start;
        private int _offset;
        private int _relevantLength;
        public JConvert(bool b) {
            _bytes= new byte[20];
            SetType("boolean");
            SetLength(new int[0]);
            _bytes[_start]= b ?(byte)1 :(byte)0;
            _relevantLength= 20;
        }
        public JConvert(string s) {
            _bytes= new byte[32];
            SetType("literal");
            byte[] b= UnicodeEncoding.UTF8.GetBytes(s);
            SetLength(b.Length);
            b.CopyTo(_bytes, _start);
            _relevantLength= Math.Max(20, 
4*Convert.ToInt32((_start+b.Length+3)/4));
        }
        public JConvert(DataTable dt) {
            _bytes= new byte[32];
            SetType("boxed");
            SetLength(new int[] { dt.Columns.Count, 3 });
            _offset= _start+_total*4;
            for (int j= 0; j < dt.Columns.Count; j++) {
                DataColumn col= dt.Columns[j];
                SetNextArray(_start+12*j, new JConvert(col.ColumnName));
                SetNextArray(_start+12*j+4,
                    col.AllowDBNull ?new JConvert(col, true) :new JConvert(true)
                );
                SetNextArray(_start+12*j+8, new JConvert(col, false));
            }
            _relevantLength= _offset;
        }
        public JConvert(DataColumn col, bool nulls) {
            _bytes= new byte[32];
            DataTable dt= col.Table;
            SetLength(dt.Rows.Count);
            if (nulls) {
                SetType("boolean");
                for (int j= 0; j < dt.Rows.Count; j++) {
                    _bytes[_start+j]= (DBNull.Value == dt.Rows[j][col]) 
?(byte)0 :(byte)1;
                    _relevantLength= Math.Max(20, 
4*Convert.ToInt32((_start+dt.Rows.Count+3)/4));
                }
            } else {
                switch (Type.GetTypeCode(col.DataType.UnderlyingSystemType)) {
                    case TypeCode.Boolean:
                        SetType("boolean");
                        for (int j= 0; j < dt.Rows.Count; j++) {
                            object o= dt.Rows[j][col];
                            if (DBNull.Value != o)
                                _bytes[_start+j]= (bool)o ?(byte)1 :(byte)0;
                        }
                        _relevantLength= Math.Max(20, 
4*Convert.ToInt32((_start+dt.Rows.Count+3)/4));
                        break;
                    case TypeCode.Byte:
                    case TypeCode.Char:
                        SetType("literal");
                        for (int j= 0; j < dt.Rows.Count; j++) {
                            object o= dt.Rows[j][col];
                            if (DBNull.Value != o)
                                _bytes[_start+j]= (byte)o;
                        }
                        _relevantLength= Math.Max(20, 
4*Convert.ToInt32((_start+dt.Rows.Count+3)/4));
                        break;
                    case TypeCode.Int16:
                    case TypeCode.Int32:
                        SetType("integer");
                        for (int j= 0; j < dt.Rows.Count; j++) {
                            object o= dt.Rows[j][col];
                            if (DBNull.Value != o)
                                SetInt(_start+j*4, Convert.ToInt32(o));
                        }
                        _relevantLength= _start+dt.Rows.Count*4;
                        break;
                    case TypeCode.Double: 
                        SetType("floating point");
                        for (int j= 0; j < dt.Rows.Count; j++) {
                            object o= dt.Rows[j][col];
                            if (DBNull.Value != o)
                                SetFloat(_start+j*8, Convert.ToDouble(o));
                        }
                        _relevantLength= _start+dt.Rows.Count*8;
                        break;
                    default:
                        SetType("boxed");
                        _offset= _start+_total*4;
                        for (int j= 0; j < dt.Rows.Count; j++) {
                            object o= dt.Rows[j][col];
                            if (DBNull.Value != o)
                                SetNextArray(_start+j*4, new 
JConvert(Convert.ToString(o)));
                        }
                        _relevantLength= _offset;
                        break;
                }
            }
        }
        private void HaveEnough(int enough) {
            if (enough <= _bytes.Length) return;
            byte[] b= new byte[enough+_bytes.Length];
            _bytes.CopyTo(b, 0);
            _bytes= b;
        }
        private void SetInt(int offset, int n) {
            HaveEnough(offset+4);
            byte[] t= BitConverter.GetBytes(n);
            for (int j= 0; j < 4; j++)
                _bytes[offset+j]= t[j];
        }
        private void SetFloat(int offset, double n) {
            HaveEnough(offset+8);
            byte[] t= BitConverter.GetBytes(n);
            for (int j= 0; j < 8; j++)
                _bytes[offset+j]= t[j];
        }
        private void SetType(int type) {
            SetInt(0, 0xe1);
            SetInt(4, type);
            _siz= type==2 ?1 :Math.Min(type, 32); /* used to estimate storage 
requirements */
            HaveEnough(_start+_total*_siz);
        }
        private void SetType(string type) {
            switch (type) {
                case "boolean": SetType(1); break;
                case "literal": SetType(2); break;
                case "integer": SetType(4); break;
                case "floating point": SetType(8); break;
                case "complex": SetType(16); break;
                case "boxed": SetType(32); break;
                case "extended integer": SetType(64); break;
                case "rational": SetType(128); break;
                default: throw new NotImplementedException();
            }
        }
        private void SetRank(int rank) {
            SetInt(12, rank);
        }
        private void SetLength(int[] length) {
            SetRank(length.Length);
            _total= 1;
            for (int j= 0; j < length.Length; j++) {
                _total*= length[j];
                SetInt(16+j*4, length[j]);
            }
            SetInt(8, _total);
            _start= 16+4*length.Length;
            HaveEnough(_start+_total*_siz);
        }
        private void SetLength(int length) {
            SetLength(new int[]{length});
        }
        private void SetNextArray(int offset, JConvert array) {
            SetInt(offset, _offset);
            byte[] b= array.GetBytes();
            HaveEnough(_offset+b.Length);
            b.CopyTo(_bytes, _offset);
            _offset+= array.GetRelevantLength();
        }
        public byte[] GetBytes() {
            return _bytes;
        }
        public int GetRelevantLength() {
            return _relevantLength;
        }
    }
}
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to