调试通过,增加 message
diff --git a/message.go b/message.go
new file mode 100644
index 0000000..725155d
--- /dev/null
+++ b/message.go
@@ -0,0 +1,300 @@
+// message.go
+package swservice
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	//	"reflect"
+	"strconv"
+)
+
+type MessageWriter struct {
+	FuncNo      int `json: "funcno"`
+	Attributes  map[string]interface{}
+	ColumnNames []string
+	ColumnDescs []string
+	RowData     []map[string]interface{}
+	Row         map[string]interface{}
+}
+
+func NewMessageWriter(funcno int) *MessageWriter {
+	return &MessageWriter{
+		FuncNo:      funcno,
+		Attributes:  make(map[string]interface{}),
+		ColumnNames: make([]string, 0),
+		ColumnDescs: make([]string, 0),
+		RowData:     make([]map[string]interface{}, 0)}
+}
+func (m *MessageWriter) SetAttr(name string, value interface{}) {
+	m.Attributes[name] = value
+}
+func (m *MessageWriter) AddCol(name string, value interface{}) {
+	if m.Row == nil {
+		m.Row = make(map[string]interface{})
+	}
+	m.Row[name] = value
+}
+
+func is_contains(k string, slice []string) bool {
+	for _, v := range slice {
+		if k == v {
+			return true
+		}
+	}
+	return false
+}
+
+func (m *MessageWriter) AddRow() {
+	if m.Row == nil {
+		return
+	}
+	//	data := make([]interface{}, 0)
+	//	if len(m.ColumnNames) == 0 {
+	//		for k, v := range m.Row {
+	//			m.ColumnNames = append(m.ColumnNames, k)
+	//			data = append(data, v)
+	//		}
+	//	} else {
+	//		for _, n := range m.ColumnNames {
+	//			if v, ok := m.Row[n]; !ok {
+	//				data = append(data, nil)
+	//			} else {
+	//				data = append(data, v)
+	//			}
+	//		}
+	//		for k, v := range m.Row {
+	//			if !is_contains(k, m.ColumnNames) {
+	//				m.ColumnNames = append(m.ColumnNames, k)
+	//				data = append(data, v)
+	//			}
+	//		}
+	//	}
+	//	m.RowData = append(m.RowData, data)
+	m.RowData = append(m.RowData, m.Row)
+	m.Row = nil
+}
+
+func (m *MessageWriter) serialize_rowdata() {
+	m.ColumnNames = make([]string, 0)
+	for _, row := range m.RowData {
+		for k, _ := range row {
+			if !is_contains(k, m.ColumnNames) {
+				m.ColumnNames = append(m.ColumnNames, k)
+			}
+		}
+	}
+	rows := make([][]interface{}, 0)
+	for _, row := range m.RowData {
+		data := make([]interface{}, 0)
+		for _, k := range m.ColumnNames {
+			if v, ok := row[k]; !ok {
+				data = append(data, nil)
+			} else {
+				data = append(data, v)
+			}
+		}
+		rows = append(rows, data)
+	}
+	m.Attributes["rowdata"] = rows
+	m.Attributes["rowcnt"] = len(rows)
+}
+
+func (m *MessageWriter) Serialize() string {
+	m.Attributes["funcno"] = m.FuncNo
+	m.serialize_rowdata()
+	m.Attributes["colnames"] = m.ColumnNames
+	m.Attributes["coldescs"] = m.ColumnNames
+	m.Attributes["colcnt"] = len(m.ColumnNames)
+	r, _ := json.Marshal(m.Attributes)
+	return string(r)
+}
+
+//////////////////////////////////////////////////////////////////////
+type MessageReader struct {
+	FuncNo      int
+	RetCode     int
+	RetMsg      string
+	DBMsg       string
+	ErrName     string
+	ColumnNames []string
+	ColumnDescs []string
+	Attributes  map[string]interface{}
+	RowData     []map[string]interface{}
+	RowIndex    int
+}
+
+func get_value_as_int(value interface{}) int {
+	//	vtype := reflect.TypeOf(value)
+	switch value.(type) {
+	case int:
+		return value.(int)
+	case float64:
+		return int(value.(float64))
+	case string:
+		i, _ := strconv.Atoi(value.(string))
+		return i
+	default:
+		panic("Error")
+	}
+}
+
+func get_column_names(data interface{}) (result []string) {
+	if data == nil {
+		return nil
+	}
+	names := data.([]interface{})
+	result = make([]string, 0)
+	for _, v := range names {
+		result = append(result, v.(string))
+	}
+	return
+}
+
+func convert_to_int(value interface{}) int {
+	if value == nil {
+		return 0
+	}
+	switch value.(type) {
+	case int:
+		return value.(int)
+	case float64:
+		return int(value.(float64))
+	case string:
+		i, _ := strconv.Atoi(value.(string))
+		return i
+	default:
+		return 0
+	}
+}
+
+func convert_to_string(value interface{}) string {
+	if value == nil {
+		return ""
+	}
+	return fmt.Sprintf("%v", value)
+}
+
+func NewMessageReader(data []byte) *MessageReader {
+	var s interface{}
+	err := json.Unmarshal(data, &s)
+	if err != nil {
+		return nil
+	}
+	obj := s.(map[string]interface{})
+
+	m := &MessageReader{Attributes: make(map[string]interface{}),
+		RowData: make([]map[string]interface{}, 0)}
+	m.FuncNo = convert_to_int(obj["funcno"])
+	m.RetCode = convert_to_int(obj["retcode"])
+	m.RetMsg = convert_to_string(obj["retmsg"])
+	m.DBMsg = convert_to_string(obj["dbmsg"])
+	m.ErrName = convert_to_string(obj["errname"])
+
+	m.ColumnNames = get_column_names(obj["colnames"])
+	m.ColumnDescs = get_column_names(obj["coldescs"])
+
+	if rowdata, err := obj["rowdata"]; err {
+		if rowdata != nil {
+			for _, raw := range rowdata.([]interface{}) {
+				row := raw.([]interface{})
+				data := make(map[string]interface{})
+				for idx, v := range row {
+					data[m.ColumnNames[idx]] = v
+				}
+				m.RowData = append(m.RowData, data)
+			}
+		}
+	}
+	reverseKey := map[string]bool{
+		"funcno":   true,
+		"colnames": true,
+		"coldescs": true,
+		"rowcnt":   true,
+		"colcnt":   true,
+		"rowdata":  true,
+		"retcode":  true,
+		"retmsg":   true,
+		"dbmsg":    true,
+		"errname":  true}
+
+	for k, v := range obj {
+		if _, ok := reverseKey[k]; ok {
+			continue
+		}
+		m.Attributes[k] = v
+	}
+	return m
+}
+
+func (m *MessageReader) RowCount() int {
+	return len(m.RowData)
+}
+
+func (m *MessageReader) HasMore() bool {
+	return m.RowIndex < m.RowCount()
+}
+
+func (m *MessageReader) NextRow() error {
+	m.RowIndex++
+	if m.RowIndex > m.RowCount() {
+		return errors.New("Eof of row")
+	}
+	return nil
+}
+
+func (m *MessageReader) GetCol(name string) interface{} {
+	idx := m.RowIndex - 1
+	if v, ok := m.RowData[idx][name]; !ok {
+		return nil
+	} else {
+		return v
+	}
+}
+
+func (m *MessageReader) GetColAsInt(name string) int {
+	v := m.GetCol(name)
+	switch v.(type) {
+	case float32:
+		return int(v.(float32))
+	case float64:
+		return int(v.(float64))
+	case int:
+		return v.(int)
+	case string:
+		i, _ := strconv.Atoi(v.(string))
+		return i
+	default:
+		return 0
+	}
+}
+
+func (m *MessageReader) GetColAsString(name string) string {
+	v := m.GetCol(name)
+	return fmt.Sprintf("%v", v)
+}
+
+func (m *MessageReader) GetColAsDouble(name string) float64 {
+	v := m.GetCol(name)
+	switch v.(type) {
+	case float32:
+		return float64(v.(float32))
+	case float64:
+		return v.(float64)
+	case int:
+		return float64(v.(int))
+	case string:
+		i, _ := strconv.ParseFloat(v.(string), 64)
+		return i
+	default:
+		return 0
+	}
+}
+
+func (m *MessageReader) GetAttr(name string) interface{} {
+	if v, ok := m.Attributes[name]; !ok {
+		return nil
+	} else {
+		return v
+	}
+}