/*
* Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software;Designed and Developed mainly by many Chinese
* opensource volunteers. you can redistribute it and/or modify it under the
* terms of the GNU General Public License version 2 only, as published by the
* Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Any questions about this component can be directed to it's project Web address
* https://code.google.com/p/opencloudb/.
*
*/
package org.opencloudb.mpp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.opencloudb.net.mysql.RowDataPacket;
import org.opencloudb.util.ByteUtil;
import org.opencloudb.util.CompareUtil;
public class RowDataPacketSorter {
protected final OrderCol[] orderCols;
private List<RowDataPacket> sorted = new ArrayList<RowDataPacket>();
private RowDataPacket[] array, resultTemp;
private int p1, pr, p2;
public RowDataPacketSorter(OrderCol[] orderCols) {
super();
this.orderCols = orderCols;
}
public void addRow(RowDataPacket row) {
this.sorted.add(row);
}
public Collection<RowDataPacket> getSortedResult() {
try {
this.mergeSort(sorted.toArray(new RowDataPacket[sorted.size()]));
} catch (Exception e) {
e.printStackTrace();
}
if (array != null) {
Collections.addAll(this.sorted, array);
}
return sorted;
}
private RowDataPacket[] mergeSort(RowDataPacket[] result) throws Exception {
this.sorted.clear();
array = result;
if (result == null || result.length < 2 || this.orderCols == null
|| orderCols.length < 1) {
return result;
}
mergeR(0, result.length - 1);
return array;
}
private void mergeR(int startIndex, int endIndex) {
if (startIndex < endIndex) {
int mid = (startIndex + endIndex) / 2;
mergeR(startIndex, mid);
mergeR(mid + 1, endIndex);
merge(startIndex, mid, endIndex);
}
}
private void merge(int startIndex, int midIndex, int endIndex) {
resultTemp = new RowDataPacket[(endIndex - startIndex + 1)];
pr = 0;
p1 = startIndex;
p2 = midIndex + 1;
while (p1 <= midIndex || p2 <= endIndex) {
if (p1 == midIndex + 1) {
while (p2 <= endIndex) {
resultTemp[pr++] = array[p2++];
}
} else if (p2 == endIndex + 1) {
while (p1 <= midIndex) {
resultTemp[pr++] = array[p1++];
}
} else {
compare(0);
}
}
for (p1 = startIndex, p2 = 0; p1 <= endIndex; p1++, p2++) {
array[p1] = resultTemp[p2];
}
}
/**
* 递归按照排序字段进行排序
*
* @param byColumnIndex
*/
private void compare(int byColumnIndex) {
if (byColumnIndex == this.orderCols.length) {
if (this.orderCols[byColumnIndex - 1].orderType == OrderCol.COL_ORDER_TYPE_ASC) {
resultTemp[pr++] = array[p1++];
} else {
resultTemp[pr++] = array[p2++];
}
return;
}
byte[] left = array[p1].fieldValues
.get(this.orderCols[byColumnIndex].colMeta.colIndex);
byte[] right = array[p2].fieldValues
.get(this.orderCols[byColumnIndex].colMeta.colIndex);
if (compareObject(left, right, this.orderCols[byColumnIndex]) <= 0) {
if (compareObject(left, right, this.orderCols[byColumnIndex]) < 0) {
if (this.orderCols[byColumnIndex].orderType == OrderCol.COL_ORDER_TYPE_ASC) {// 升序
resultTemp[pr++] = array[p1++];
} else {
resultTemp[pr++] = array[p2++];
}
} else {// 如果当前字段相等,则按照下一个字段排序
compare(byColumnIndex + 1);
}
} else {
if (this.orderCols[byColumnIndex].orderType == OrderCol.COL_ORDER_TYPE_ASC) {// 升序
resultTemp[pr++] = array[p2++];
} else {
resultTemp[pr++] = array[p1++];
}
}
}
protected int compareObject(Object l, Object r, OrderCol orderCol) {
int colType = orderCol.getColMeta().getColType();
byte[] left = (byte[]) l;
byte[] right = (byte[]) r;
// System.out.println("------------" + colType);
switch (colType) {
case ColMeta.COL_TYPE_DECIMAL:
case ColMeta.COL_TYPE_INT:
case ColMeta.COL_TYPE_SHORT:
case ColMeta.COL_TYPE_LONG:
case ColMeta.COL_TYPE_FLOAT:
case ColMeta.COL_TYPE_DOUBLE:
case ColMeta.COL_TYPE_LONGLONG:
case ColMeta.COL_TYPE_INT24:
case ColMeta.COL_TYPE_NEWDECIMAL:
//因为mysql的日期也是数字字符串方式表达,因此可以跟整数等一起对待
case ColMeta.COL_TYPE_DATE:
case ColMeta.COL_TYPE_TIMSTAMP:
case ColMeta.COL_TYPE_TIME:
case ColMeta.COL_TYPE_YEAR:
case ColMeta.COL_TYPE_DATETIME:
case ColMeta.COL_TYPE_NEWDATE:
case ColMeta.COL_TYPE_BIT:
return ByteUtil.compareNumberByte(left, right);
case ColMeta.COL_TYPE_VAR_STRING:
case ColMeta.COL_TYPE_STRING:
//ENUM和SET类型都是字符串,按字符串处理
case ColMeta.COL_TYPE_ENUM:
case ColMeta.COL_TYPE_SET:
return CompareUtil.compareString(ByteUtil.getString(left),
ByteUtil.getString(right));
//BLOB相关类型和GEOMETRY类型不支持排序,略掉
}
return 0;
}
}