func()

in packetbeat/protos/mysql/mysql.go [805:999]


func (mysql *mysqlPlugin) parseMysqlExecuteStatement(data []byte, stmtdata *mysqlStmtData) []string {
	dataLen := len(data)
	if dataLen < 14 {
		logp.Debug("mysql", "Data too small")
		return nil
	}
	var paramType, paramUnsigned uint8
	nparamType := []uint8{}
	paramString := []string{}
	nparam := stmtdata.numOfParameters
	offset := 0
	// mysql hdr
	offset += 4
	// cmd type
	offset++
	// stmt id
	offset += 4
	// flags
	offset++
	// iterations
	offset += 4
	// null-bitmap
	if nparam > 0 {
		offset += (nparam + 7) / 8
	} else {
		return nil
	}
	// stmt bound
	if dataLen <= offset {
		logp.Debug("mysql", "Data too small")
		return nil
	}
	stmtBound := data[offset]
	offset++
	paramOffset := offset
	if stmtBound == 1 {
		paramOffset += nparam * 2
		if dataLen <= paramOffset {
			logp.Debug("mysql", "Data too small to contain parameters")
			return nil
		}
		// First call or rebound (1)
		for stmtPos := 0; stmtPos < nparam; stmtPos++ {
			paramType = uint8(data[offset])
			offset++
			nparamType = append(nparamType, paramType)
			logp.Debug("mysqldetailed", "type = %d", paramType)
			paramUnsigned = uint8(data[offset])
			offset++
			if paramUnsigned != 0 {
				logp.Debug("mysql", "Illegal param unsigned")
				return nil
			}
		}
		// Save param type info
		stmtdata.nparamType = nparamType
	} else {
		// Subsequent call (0)
		if len(stmtdata.nparamType) > 0 {
			// get saved param type info
			nparamType = stmtdata.nparamType
		} else {
			return nil
		}
	}

	for stmtPos := 0; stmtPos < nparam; stmtPos++ {
		paramType = nparamType[stmtPos]
		// dissect parameter on paramType
		switch paramType {
		// FIELD_TYPE_TINY
		case 0x01:
			valueString := strconv.Itoa(int(data[paramOffset]))
			paramString = append(paramString, valueString)
			paramOffset++
		// FIELD_TYPE_SHORT
		case 0x02:
			if dataLen < paramOffset+2 {
				logp.Debug("mysql", "Data too small")
				return nil
			}
			valueString := strconv.Itoa(int(binary.LittleEndian.Uint16(data[paramOffset:])))
			paramString = append(paramString, valueString)
			paramOffset += 2
		// FIELD_TYPE_LONG
		case 0x03:
			if dataLen < paramOffset+4 {
				logp.Debug("mysql", "Data too small")
				return nil
			}
			valueString := strconv.Itoa(int(binary.LittleEndian.Uint32(data[paramOffset:])))
			paramString = append(paramString, valueString)
			paramOffset += 4
		// FIELD_TYPE_FLOAT
		case 0x04:
			paramString = append(paramString, "TYPE_FLOAT")
			paramOffset += 4
		// FIELD_TYPE_DOUBLE
		case 0x05:
			paramString = append(paramString, "TYPE_DOUBLE")
			paramOffset += 4
		// FIELD_TYPE_NULL
		case 0x06:
			paramString = append(paramString, "TYPE_NULL")
		//  FIELD_TYPE_LONGLONG
		case 0x08:
			if dataLen < paramOffset+8 {
				logp.Debug("mysql", "Data too small")
				return nil
			}
			valueString := strconv.FormatInt(int64(binary.LittleEndian.Uint64(data[paramOffset:paramOffset+8])), 10)
			paramString = append(paramString, valueString)
			paramOffset += 8
		// FIELD_TYPE_TIMESTAMP
		// FIELD_TYPE_DATETIME
		// FIELD_TYPE_DATE
		case 0x07, 0x0c, 0x0a:
			var year, month, day, hour, minute, second string
			paramLen := int(data[paramOffset])
			if dataLen < paramOffset+paramLen+1 {
				logp.Debug("mysql", "Data too small")
				return nil
			}
			paramOffset++
			if paramLen >= 2 {
				year = strconv.Itoa(int(binary.LittleEndian.Uint16(data[paramOffset:])))
			}
			if paramLen >= 4 {
				month = strconv.Itoa(int(data[paramOffset+2]))
				day = strconv.Itoa(int(data[paramOffset+3]))
			}
			if paramLen >= 7 {
				hour = strconv.Itoa(int(data[paramOffset+4]))
				minute = strconv.Itoa(int(data[paramOffset+5]))
				second = strconv.Itoa(int(data[paramOffset+6]))
			}

			// If paramLen is greater or equal to 11
			// then nanoseconds are also available.
			// We do not handle them.

			datetime := year + "/" + month + "/" + day + " " + hour + ":" + minute + ":" + second
			paramString = append(paramString, datetime)
			paramOffset += paramLen
		// FIELD_TYPE_TIME
		case 0x0b:
			paramLen := int(data[paramOffset])
			if dataLen < paramOffset+paramLen+1 {
				logp.Debug("mysql", "Data too small")
				return nil
			}
			paramOffset++
			paramString = append(paramString, "TYPE_TIME")
			paramOffset += paramLen
		// FIELD_TYPE_VAR_STRING
		// FIELD_TYPE_BLOB
		// FIELD_TYPE_STRING
		case 0xf6, 0xfc, 0xfd, 0xfe:
			paramLen := int(data[paramOffset])
			paramOffset++
			switch paramLen {
			case 0xfc: /* 252 - 64k chars */
				paramLen16 := int(binary.LittleEndian.Uint16(data[paramOffset : paramOffset+2]))
				if dataLen < paramOffset+paramLen16+2 {
					logp.Debug("mysql", "Data too small")
					return nil
				}
				paramOffset += 2
				paramString = append(paramString, string(data[paramOffset:paramOffset+paramLen16]))
				paramOffset += paramLen16
			case 0xfd: /* 64k - 16M chars */
				paramLen24 := int(leUint24(data[paramOffset : paramOffset+3]))
				if dataLen < paramOffset+paramLen24+3 {
					logp.Debug("mysql", "Data too small")
					return nil
				}
				paramOffset += 3
				paramString = append(paramString, string(data[paramOffset:paramOffset+paramLen24]))
				paramOffset += paramLen24
			default: /* < 252 chars     */
				if dataLen < paramOffset+paramLen {
					logp.Debug("mysql", "Data too small")
					return nil
				}
				paramString = append(paramString, string(data[paramOffset:paramOffset+paramLen]))
				paramOffset += paramLen
			}
		default:
			logp.Debug("mysql", "Unknown param type")
			return nil
		}

	}
	return paramString
}