-------------------------------------------------------------------------
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- | This module contains the implementations of
--   serialization and deserialization of Clickhouse data types.
module Database.ClickHouseDriver.Column where

import Database.ClickHouseDriver.Types (ClickhouseType (..), Context (..), ServerInfo (..))
import Database.ClickHouseDriver.IO.BufferedReader
  ( Reader,
    readBinaryInt16,
    readBinaryInt32,
    readBinaryInt64,
    readBinaryInt8,
    readBinaryStr,
    readBinaryStrWithLength,
    readBinaryUInt128,
    readBinaryUInt16,
    readBinaryUInt32,
    readBinaryUInt64,
    readBinaryUInt8,
  )
import Database.ClickHouseDriver.IO.BufferedWriter
  ( Writer,
    writeBinaryFixedLengthStr,
    writeBinaryInt16,
    writeBinaryInt32,
    writeBinaryInt64,
    writeBinaryInt8,
    writeBinaryStr,
    writeBinaryUInt128,
    writeBinaryUInt16,
    writeBinaryUInt32,
    writeBinaryUInt64,
    writeBinaryUInt8,
    writeVarUInt,
  )
import Control.Monad.State.Lazy (MonadIO (..))
import Data.Binary (Word64, Word8)
import Data.Bits (shift, (.&.), (.|.))
import Data.ByteString (ByteString, isPrefixOf)
import qualified Data.ByteString as BS
  ( drop,
    filter,
    intercalate,
    length,
    splitWith,
    take,
    unpack,
  )
import Data.ByteString.Builder (Builder)
import Data.ByteString.Char8 (readInt)
import qualified Data.ByteString.Char8 as C8
import Data.ByteString.Unsafe
  ( unsafePackCString,
    unsafeUseAsCStringLen,
  )
import qualified Data.HashMap.Strict as Map
import Data.Hashable (Hashable (hash))
import Data.Int (Int32, Int64)
import qualified Data.List as List
import Data.Maybe (fromJust, fromMaybe)
import Data.Time
  ( TimeZone (..),
    addDays,
    diffDays,
    fromGregorian,
    getCurrentTimeZone,
    toGregorian,
  )
import Data.UUID as UUID
  ( fromString,
    fromWords,
    toString,
    toWords,
  )
import Data.Vector (Vector, (!))
import qualified Data.Vector as V
  ( cons,
    drop,
    foldl',
    fromList,
    generate,
    length,
    map,
    mapM,
    mapM_,
    replicateM,
    scanl',
    sum,
    take,
    toList,
    zipWith,
    zipWithM_,
  )
import Foreign.C (CString)
import Network.IP.Addr
  ( IP4 (..),
    IP6 (..),
    ip4FromOctets,
    ip4ToOctets,
    ip6FromWords,
    ip6ToWords,
  )
import Data.List (foldl')
#define EQUAL 61
#define COMMA 44
#define SPACE 32
#define QUOTE 39
--Debug
--import Debug.Trace

-- Notice: Codes in this file might be difficult to read.
---------------------------------------------------------------------------------------
---Readers
readColumn ::
  -- | Server information is needed in case of some parameters are missing
  ServerInfo ->
  -- | number of rows
  Int ->
  -- | data type
  ByteString ->
  Reader (Vector ClickhouseType)
readColumn :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readColumn ServerInfo
server_info Int
n_rows ByteString
spec
  | ByteString
"String" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (ByteString -> ClickhouseType
CKString (ByteString -> ClickhouseType)
-> StateT Buffer IO ByteString -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO ByteString
readBinaryStr)
  | ByteString
"Array" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readArray ServerInfo
server_info Int
n_rows ByteString
spec
  | ByteString
"FixedString" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int -> ByteString -> Reader (Vector ClickhouseType)
readFixed Int
n_rows ByteString
spec
  | ByteString
"DateTime" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readDateTime ServerInfo
server_info Int
n_rows ByteString
spec
  | ByteString
"Date" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int -> Reader (Vector ClickhouseType)
readDate Int
n_rows
  | ByteString
"Tuple" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readTuple ServerInfo
server_info Int
n_rows ByteString
spec
  | ByteString
"Nullable" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readNullable ServerInfo
server_info Int
n_rows ByteString
spec
  | ByteString
"LowCardinality" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readLowCardinality ServerInfo
server_info Int
n_rows ByteString
spec
  | ByteString
"Decimal" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int -> ByteString -> Reader (Vector ClickhouseType)
readDecimal Int
n_rows ByteString
spec
  | ByteString
"Enum" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int -> ByteString -> Reader (Vector ClickhouseType)
readEnum Int
n_rows ByteString
spec
  | ByteString
"Int" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int -> ByteString -> Reader (Vector ClickhouseType)
readIntColumn Int
n_rows ByteString
spec
  | ByteString
"UInt" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int -> ByteString -> Reader (Vector ClickhouseType)
readIntColumn Int
n_rows ByteString
spec
  | ByteString
"IPv4" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int -> Reader (Vector ClickhouseType)
readIPv4 Int
n_rows
  | ByteString
"IPv6" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int -> Reader (Vector ClickhouseType)
readIPv6 Int
n_rows
  | ByteString
"SimpleAggregateFunction" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readSimpleAggregateFunction ServerInfo
server_info Int
n_rows ByteString
spec
  | ByteString
"UUID" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int -> Reader (Vector ClickhouseType)
readUUID Int
n_rows
  | Bool
otherwise = [Char] -> Reader (Vector ClickhouseType)
forall a. HasCallStack => [Char] -> a
error ([Char]
"Unknown Type: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
Prelude.++ ByteString -> [Char]
C8.unpack ByteString
spec)

writeColumn ::
  -- | context contains client information and server information
  Context ->
  -- | column name
  ByteString ->
  -- | column type (String, Int, etc)
  ByteString ->
  -- | items to be serialized.
  Vector ClickhouseType ->
  -- | result wrapped in a customized Writer Monad used for concatenating string builders.
  Writer Builder
writeColumn :: Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeColumn Context
ctx ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | ByteString
"String" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> Vector ClickhouseType -> Writer Builder
writeStringColumn ByteString
col_name Vector ClickhouseType
items
  | ByteString
"FixedString(" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeFixedLengthString ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | ByteString
"Int" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeIntColumn ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | ByteString
"UInt" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeUIntColumn ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | ByteString
"Nullable(" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeNullable Context
ctx ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | ByteString
"Tuple" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeTuple Context
ctx ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | ByteString
"Enum" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeEnum ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | ByteString
"Array" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeArray Context
ctx ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | ByteString
"UUID" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> Vector ClickhouseType -> Writer Builder
writeUUID ByteString
col_name Vector ClickhouseType
items
  | ByteString
"IPv4" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> Vector ClickhouseType -> Writer Builder
writeIPv4 ByteString
col_name Vector ClickhouseType
items
  | ByteString
"IPv6" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> Vector ClickhouseType -> Writer Builder
writeIPv6 ByteString
col_name Vector ClickhouseType
items
  | ByteString
"Date" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> Vector ClickhouseType -> Writer Builder
writeDate ByteString
col_name Vector ClickhouseType
items
  | ByteString
"LowCardinality" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeLowCardinality Context
ctx ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | ByteString
"DateTime" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeDateTime ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | ByteString
"Decimal" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
cktype = ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeDecimal ByteString
col_name ByteString
cktype Vector ClickhouseType
items
  | Bool
otherwise = [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error ([Char]
"Unknown Type in the column: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
Prelude.++ ByteString -> [Char]
C8.unpack ByteString
col_name)
---------------------------------------------------------------------------------------------
readFixed :: Int -> ByteString -> Reader (Vector ClickhouseType)
readFixed :: Int -> ByteString -> Reader (Vector ClickhouseType)
readFixed Int
n_rows ByteString
spec = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
  let str_number :: ByteString
str_number = Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
13) (Int -> ByteString -> ByteString
BS.drop Int
12 ByteString
spec)
  let number :: Int
number = case ByteString -> Maybe (Int, ByteString)
readInt ByteString
str_number of
        Maybe (Int, ByteString)
Nothing -> Int
0 -- This can't happen
        Just (Int
x, ByteString
_) -> Int
x
  Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (Int -> StateT Buffer IO ClickhouseType
readFixedLengthString Int
number)

readFixedLengthString :: Int -> Reader ClickhouseType
readFixedLengthString :: Int -> StateT Buffer IO ClickhouseType
readFixedLengthString Int
str_len = ByteString -> ClickhouseType
CKString (ByteString -> ClickhouseType)
-> StateT Buffer IO ByteString -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> StateT Buffer IO ByteString
readBinaryStrWithLength Int
str_len

writeStringColumn :: ByteString -> Vector ClickhouseType -> Writer Builder
writeStringColumn :: ByteString -> Vector ClickhouseType -> Writer Builder
writeStringColumn ByteString
col_name =
  (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
    ( \case
        CKString ByteString
s -> ByteString -> Writer Builder
forall w. MonoidMap ByteString w => ByteString -> Writer w
writeBinaryStr ByteString
s
        ClickhouseType
CKNull -> Word -> Writer Builder
forall w. MonoidMap ByteString w => Word -> Writer w
writeVarUInt Word
0
        ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name)
    )

writeFixedLengthString :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeFixedLengthString :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeFixedLengthString ByteString
col_name ByteString
spec Vector ClickhouseType
items = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
  let Just (Int
len, ByteString
_) = ByteString -> Maybe (Int, ByteString)
readInt (ByteString -> Maybe (Int, ByteString))
-> ByteString -> Maybe (Int, ByteString)
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
13) (Int -> ByteString -> ByteString
BS.drop Int
12 ByteString
spec)
  (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
    ( \case
        CKString ByteString
s -> Word -> ByteString -> Writer Builder
forall w. MonoidMap ByteString w => Word -> ByteString -> Writer w
writeBinaryFixedLengthStr (Int -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len) ByteString
s
        ClickhouseType
CKNull -> () -> Vector () -> ()
forall a b. a -> b -> a
const () (Vector () -> ())
-> WriterT Builder IO (Vector ()) -> Writer Builder
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Writer Builder -> WriterT Builder IO (Vector ())
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM (Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len) (Word -> Writer Builder
forall w. MonoidMap ByteString w => Word -> Writer w
writeVarUInt Word
0)
        ClickhouseType
x -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" got: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ClickhouseType -> [Char]
forall a. Show a => a -> [Char]
show ClickhouseType
x)
    )
    Vector ClickhouseType
items

---------------------------------------------------------------------------------------------

-- | read data in format of bytestring into format of haskell type.
readIntColumn :: Int -> ByteString -> Reader (Vector ClickhouseType)
readIntColumn :: Int -> ByteString -> Reader (Vector ClickhouseType)
readIntColumn Int
n_rows ByteString
"Int8" = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (Int8 -> ClickhouseType
CKInt8 (Int8 -> ClickhouseType)
-> StateT Buffer IO Int8 -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO Int8
readBinaryInt8)
readIntColumn Int
n_rows ByteString
"Int16" = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (Int16 -> ClickhouseType
CKInt16 (Int16 -> ClickhouseType)
-> StateT Buffer IO Int16 -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO Int16
readBinaryInt16)
readIntColumn Int
n_rows ByteString
"Int32" = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (Int32 -> ClickhouseType
CKInt32 (Int32 -> ClickhouseType)
-> StateT Buffer IO Int32 -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO Int32
readBinaryInt32)
readIntColumn Int
n_rows ByteString
"Int64" = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (Int64 -> ClickhouseType
CKInt64 (Int64 -> ClickhouseType)
-> StateT Buffer IO Int64 -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO Int64
readBinaryInt64)
readIntColumn Int
n_rows ByteString
"UInt8" = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (Word8 -> ClickhouseType
CKUInt8 (Word8 -> ClickhouseType)
-> StateT Buffer IO Word8 -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO Word8
readBinaryUInt8)
readIntColumn Int
n_rows ByteString
"UInt16" = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (Word16 -> ClickhouseType
CKUInt16 (Word16 -> ClickhouseType)
-> StateT Buffer IO Word16 -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO Word16
readBinaryUInt16)
readIntColumn Int
n_rows ByteString
"UInt32" = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (Word32 -> ClickhouseType
CKUInt32 (Word32 -> ClickhouseType)
-> StateT Buffer IO Word32 -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO Word32
readBinaryUInt32)
readIntColumn Int
n_rows ByteString
"UInt64" = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (Word64 -> ClickhouseType
CKUInt64 (Word64 -> ClickhouseType)
-> StateT Buffer IO Word64 -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO Word64
readBinaryUInt64)
readIntColumn Int
_ ByteString
x = [Char] -> Reader (Vector ClickhouseType)
forall a. HasCallStack => [Char] -> a
error ([Char]
"expect an integer but got: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ByteString -> [Char]
forall a. Show a => a -> [Char]
show ByteString
x)

writeIntColumn :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeIntColumn :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeIntColumn ByteString
col_name ByteString
spec Vector ClickhouseType
items = do
  let Just (Int
indicator, ByteString
_) = ByteString -> Maybe (Int, ByteString)
readInt (ByteString -> Maybe (Int, ByteString))
-> ByteString -> Maybe (Int, ByteString)
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
BS.drop Int
3 ByteString
spec -- indicator indicates which integer type, is it Int8 or Int64 etc.
  Int -> ByteString -> Vector ClickhouseType -> Writer Builder
writeIntColumn' Int
indicator ByteString
col_name Vector ClickhouseType
items
  where
    writeIntColumn' :: Int -> ByteString -> Vector ClickhouseType -> Writer Builder
    writeIntColumn' :: Int -> ByteString -> Vector ClickhouseType -> Writer Builder
writeIntColumn' Int
indicator ByteString
col_name =
      case Int
indicator of
        Int
8 ->
          (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_ -- mapM_ acts like for-loop in this context, since it repeats monadic actions.
            ( \case
                CKInt8 Int8
x -> Int8 -> Writer Builder
forall w. MonoidMap ByteString w => Int8 -> Writer w
writeBinaryInt8 Int8
x
                ClickhouseType
CKNull -> Int8 -> Writer Builder
forall w. MonoidMap ByteString w => Int8 -> Writer w
writeBinaryInt8 Int8
0
                ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name)
            )
        Int
16 ->
          (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
            ( \case
                CKInt16 Int16
x -> Int16 -> Writer Builder
forall w. MonoidMap ByteString w => Int16 -> Writer w
writeBinaryInt16 Int16
x
                ClickhouseType
CKNull -> Int16 -> Writer Builder
forall w. MonoidMap ByteString w => Int16 -> Writer w
writeBinaryInt16 Int16
0
                ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name)
            )
        Int
32 ->
          (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
            ( \case
                CKInt32 Int32
x -> Int32 -> Writer Builder
forall w. MonoidMap ByteString w => Int32 -> Writer w
writeBinaryInt32 Int32
x
                ClickhouseType
CKNull -> Int32 -> Writer Builder
forall w. MonoidMap ByteString w => Int32 -> Writer w
writeBinaryInt32 Int32
0
                ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name)
            )
        Int
64 ->
          (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
            ( \case
                CKInt64 Int64
x -> Int64 -> Writer Builder
forall w. MonoidMap ByteString w => Int64 -> Writer w
writeBinaryInt64 Int64
x
                ClickhouseType
CKNull -> Int64 -> Writer Builder
forall w. MonoidMap ByteString w => Int64 -> Writer w
writeBinaryInt64 Int64
0
                ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name)
            )

writeUIntColumn :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeUIntColumn :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeUIntColumn ByteString
col_name ByteString
spec Vector ClickhouseType
items = do
  let Just (Int
indicator, ByteString
_) = ByteString -> Maybe (Int, ByteString)
readInt (ByteString -> Maybe (Int, ByteString))
-> ByteString -> Maybe (Int, ByteString)
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
BS.drop Int
4 ByteString
spec
  Int -> ByteString -> Vector ClickhouseType -> Writer Builder
writeUIntColumn' Int
indicator ByteString
col_name Vector ClickhouseType
items
  where
    writeUIntColumn' :: Int -> ByteString -> Vector ClickhouseType -> Writer Builder
    writeUIntColumn' :: Int -> ByteString -> Vector ClickhouseType -> Writer Builder
writeUIntColumn' Int
indicator ByteString
col_name =
      case Int
indicator of
        Int
8 ->
          (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
            ( \case
                CKUInt8 Word8
x -> Word8 -> Writer Builder
forall w. MonoidMap ByteString w => Word8 -> Writer w
writeBinaryUInt8 Word8
x
                ClickhouseType
CKNull -> Word8 -> Writer Builder
forall w. MonoidMap ByteString w => Word8 -> Writer w
writeBinaryUInt8 Word8
0
                ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name)
            )
        Int
16 ->
          (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
            ( \case
                CKUInt16 Word16
x -> Int16 -> Writer Builder
forall w. MonoidMap ByteString w => Int16 -> Writer w
writeBinaryInt16 (Int16 -> Writer Builder) -> Int16 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Word16 -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
x
                ClickhouseType
CKNull -> Int16 -> Writer Builder
forall w. MonoidMap ByteString w => Int16 -> Writer w
writeBinaryInt16 Int16
0
                ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name)
            )
        Int
32 ->
          (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
            ( \case
                CKUInt32 Word32
x -> Int32 -> Writer Builder
forall w. MonoidMap ByteString w => Int32 -> Writer w
writeBinaryInt32 (Int32 -> Writer Builder) -> Int32 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
x
                ClickhouseType
CKNull -> Int32 -> Writer Builder
forall w. MonoidMap ByteString w => Int32 -> Writer w
writeBinaryInt32 Int32
0
                ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name)
            )
        Int
64 ->
          (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
            ( \case
                CKUInt64 Word64
x -> Int64 -> Writer Builder
forall w. MonoidMap ByteString w => Int64 -> Writer w
writeBinaryInt64 (Int64 -> Writer Builder) -> Int64 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Word64 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
x
                ClickhouseType
CKNull -> Int64 -> Writer Builder
forall w. MonoidMap ByteString w => Int64 -> Writer w
writeBinaryInt64 Int64
0
                ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name)
            )

---------------------------------------------------------------------------------------------

{-
  There are two types of Datetime
  DateTime(TZ) or DateTime64(precision,TZ)
  server information is required if TZ parameter is missing.
-}
readDateTime :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readDateTime :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readDateTime ServerInfo
server_info Int
n_rows ByteString
spec = do
  let (Maybe Int
scale, Maybe ByteString
spc) = ByteString -> (Maybe Int, Maybe ByteString)
readTimeSpec ByteString
spec
  case Maybe ByteString
spc of
    Maybe ByteString
Nothing -> ServerInfo
-> Int -> Maybe Int -> ByteString -> Reader (Vector ClickhouseType)
readDateTimeWithSpec ServerInfo
server_info Int
n_rows Maybe Int
scale ByteString
""
    Just ByteString
tz_name -> ServerInfo
-> Int -> Maybe Int -> ByteString -> Reader (Vector ClickhouseType)
readDateTimeWithSpec ServerInfo
server_info Int
n_rows Maybe Int
scale ByteString
tz_name
    
readTimeSpec :: ByteString -> (Maybe Int, Maybe ByteString)
readTimeSpec :: ByteString -> (Maybe Int, Maybe ByteString)
readTimeSpec ByteString
spec'
  | ByteString
"DateTime64" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec' = do
    let l :: Int
l = ByteString -> Int
BS.length ByteString
spec'
    let inner_specs :: ByteString
inner_specs = Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
12) (Int -> ByteString -> ByteString
BS.drop Int
11 ByteString
spec')
    let split :: [ByteString]
split = ByteString -> [ByteString]
getSpecs ByteString
inner_specs
    case [ByteString]
split of
      [] -> (Maybe Int
forall a. Maybe a
Nothing, Maybe ByteString
forall a. Maybe a
Nothing)
      [ByteString
x] -> (Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ (Int, ByteString) -> Int
forall a b. (a, b) -> a
fst ((Int, ByteString) -> Int) -> (Int, ByteString) -> Int
forall a b. (a -> b) -> a -> b
$ Maybe (Int, ByteString) -> (Int, ByteString)
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe (Int, ByteString) -> (Int, ByteString))
-> Maybe (Int, ByteString) -> (Int, ByteString)
forall a b. (a -> b) -> a -> b
$ ByteString -> Maybe (Int, ByteString)
readInt ByteString
x, Maybe ByteString
forall a. Maybe a
Nothing)
      [ByteString
x, ByteString
y] -> (Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ (Int, ByteString) -> Int
forall a b. (a, b) -> a
fst ((Int, ByteString) -> Int) -> (Int, ByteString) -> Int
forall a b. (a -> b) -> a -> b
$ Maybe (Int, ByteString) -> (Int, ByteString)
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe (Int, ByteString) -> (Int, ByteString))
-> Maybe (Int, ByteString) -> (Int, ByteString)
forall a b. (a -> b) -> a -> b
$ ByteString -> Maybe (Int, ByteString)
readInt ByteString
x, ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
y)
  | Bool
otherwise = do
    let l :: Int
l = ByteString -> Int
BS.length ByteString
spec'
    let inner_specs :: ByteString
inner_specs = Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
12) (Int -> ByteString -> ByteString
BS.drop Int
10 ByteString
spec')
    (Maybe Int
forall a. Maybe a
Nothing, ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
inner_specs)
    
readDateTimeWithSpec :: ServerInfo -> Int -> Maybe Int -> ByteString -> Reader (Vector ClickhouseType)
readDateTimeWithSpec :: ServerInfo
-> Int -> Maybe Int -> ByteString -> Reader (Vector ClickhouseType)
readDateTimeWithSpec ServerInfo {timezone :: ServerInfo -> Maybe ByteString
timezone = Maybe ByteString
maybe_zone} Int
n_rows Maybe Int
Nothing ByteString
tz_name = do
  Vector ClickhouseType
data32 <- Int -> ByteString -> Reader (Vector ClickhouseType)
readIntColumn Int
n_rows ByteString
"Int32"
  let tz_to_send :: ByteString
tz_to_send =
        if ByteString
tz_name ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
""
          then ByteString
"TZ=" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
tz_name
          else ByteString -> Maybe ByteString -> ByteString
forall a. a -> Maybe a -> a
fromMaybe ByteString
"" Maybe ByteString
maybe_zone
  let toDateTimeStringM :: IO (Vector ByteString)
toDateTimeStringM =
        (ClickhouseType -> IO ByteString)
-> Vector ClickhouseType -> IO (Vector ByteString)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Vector a -> m (Vector b)
V.mapM
          ( \(CKInt32 Int32
x) -> do
              CString
c_str <-
                ByteString -> (CStringLen -> IO CString) -> IO CString
forall a. ByteString -> (CStringLen -> IO a) -> IO a
unsafeUseAsCStringLen
                  ByteString
tz_to_send
                  ((CString -> Int -> IO CString) -> CStringLen -> IO CString
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (Int64 -> CString -> Int -> IO CString
c_convert_time (Int32 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
x)))
              CString -> IO ByteString
unsafePackCString CString
c_str
          )
          Vector ClickhouseType
data32
  Vector ByteString
toDateTimeString <- IO (Vector ByteString) -> StateT Buffer IO (Vector ByteString)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Vector ByteString) -> StateT Buffer IO (Vector ByteString))
-> IO (Vector ByteString) -> StateT Buffer IO (Vector ByteString)
forall a b. (a -> b) -> a -> b
$ IO (Vector ByteString)
toDateTimeStringM
  Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Vector ClickhouseType -> Reader (Vector ClickhouseType))
-> Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall a b. (a -> b) -> a -> b
$ (ByteString -> ClickhouseType)
-> Vector ByteString -> Vector ClickhouseType
forall a b. (a -> b) -> Vector a -> Vector b
V.map ByteString -> ClickhouseType
CKString Vector ByteString
toDateTimeString

readDateTimeWithSpec ServerInfo {timezone :: ServerInfo -> Maybe ByteString
timezone = Maybe ByteString
maybe_zone} Int
n_rows (Just Int
scl) ByteString
tz_name = do
  Vector ClickhouseType
data64 <- Int -> ByteString -> Reader (Vector ClickhouseType)
readIntColumn Int
n_rows ByteString
"Int64"
  let scale :: Float
scale = Float
10 Float -> Integer -> Float
forall a b. (Num a, Integral b) => a -> b -> a
^ Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
scl
  let tz_to_send :: ByteString
tz_to_send =
        if ByteString
tz_name ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
""
          then ByteString
"TZ=" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
tz_name
          else ByteString -> Maybe ByteString -> ByteString
forall a. a -> Maybe a -> a
fromMaybe ByteString
"" Maybe ByteString
maybe_zone
  let toDateTimeStringM :: IO (Vector ByteString)
toDateTimeStringM =
        (ClickhouseType -> IO ByteString)
-> Vector ClickhouseType -> IO (Vector ByteString)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Vector a -> m (Vector b)
V.mapM
          ( \(CKInt64 Int64
x) -> do
              CString
c_str <-
                ByteString -> (CStringLen -> IO CString) -> IO CString
forall a. ByteString -> (CStringLen -> IO a) -> IO a
unsafeUseAsCStringLen
                  ByteString
tz_to_send
                  ((CString -> Int -> IO CString) -> CStringLen -> IO CString
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (Float -> CString -> Int -> IO CString
c_convert_time64 (Int64 -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
x Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
scale)))
              CString -> IO ByteString
unsafePackCString CString
c_str
          )
          Vector ClickhouseType
data64
  Vector ByteString
toDateTimeString <- IO (Vector ByteString) -> StateT Buffer IO (Vector ByteString)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Vector ByteString) -> StateT Buffer IO (Vector ByteString))
-> IO (Vector ByteString) -> StateT Buffer IO (Vector ByteString)
forall a b. (a -> b) -> a -> b
$ IO (Vector ByteString)
toDateTimeStringM
  Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Vector ClickhouseType -> Reader (Vector ClickhouseType))
-> Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall a b. (a -> b) -> a -> b
$ (ByteString -> ClickhouseType)
-> Vector ByteString -> Vector ClickhouseType
forall a b. (a -> b) -> Vector a -> Vector b
V.map ByteString -> ClickhouseType
CKString Vector ByteString
toDateTimeString

writeDateTime :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeDateTime :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeDateTime ByteString
col_name ByteString
spec Vector ClickhouseType
items = do
  let (Maybe Int
scale', Maybe ByteString
spc) = ByteString -> (Maybe Int, Maybe ByteString)
readTimeSpec ByteString
spec
  case Maybe Int
scale' of
    Maybe Int
Nothing -> do
      case Maybe ByteString
spc of
        Maybe ByteString
Nothing -> do
          TimeZone {timeZoneName :: TimeZone -> [Char]
timeZoneName = [Char]
tz'} <- IO TimeZone -> WriterT Builder IO TimeZone
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO TimeZone -> WriterT Builder IO TimeZone)
-> IO TimeZone -> WriterT Builder IO TimeZone
forall a b. (a -> b) -> a -> b
$ IO TimeZone
getCurrentTimeZone
          ByteString -> Writer Builder
writeDateTimeWithSpec (ByteString -> Writer Builder) -> ByteString -> Writer Builder
forall a b. (a -> b) -> a -> b
$ [Char] -> ByteString
C8.pack [Char]
tz'
        Just ByteString
spec -> ByteString -> Writer Builder
writeDateTimeWithSpec ByteString
spec
    Just Int
_ -> do
      --TODO: Can someone implement this? I am so pissed off!
      Writer Builder
forall a. HasCallStack => a
undefined
  where
    writeDateTimeWithSpec :: ByteString -> Writer Builder
    writeDateTimeWithSpec :: ByteString -> Writer Builder
writeDateTimeWithSpec ByteString
tz_name = do
      (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
        ( \case
            (CKInt32 Int32
i32) -> do
              Int32
converted <- IO Int32 -> WriterT Builder IO Int32
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Int32 -> WriterT Builder IO Int32)
-> IO Int32 -> WriterT Builder IO Int32
forall a b. (a -> b) -> a -> b
$ Int32 -> IO Int32
convert_time_from_int32 Int32
i32
              Int32 -> Writer Builder
forall w. MonoidMap ByteString w => Int32 -> Writer w
writeBinaryInt32 Int32
converted
            (CKString ByteString
time_str) -> do
              Int32
converted <-
                IO Int32 -> WriterT Builder IO Int32
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Int32 -> WriterT Builder IO Int32)
-> IO Int32 -> WriterT Builder IO Int32
forall a b. (a -> b) -> a -> b
$
                  ByteString -> (CStringLen -> IO Int32) -> IO Int32
forall a. ByteString -> (CStringLen -> IO a) -> IO a
unsafeUseAsCStringLen
                    ByteString
tz_name
                    ( \(CString
tz, Int
l) ->
                        ByteString -> (CStringLen -> IO Int32) -> IO Int32
forall a. ByteString -> (CStringLen -> IO a) -> IO a
unsafeUseAsCStringLen
                          ByteString
time_str
                          (\(CString
time_str, Int
l2) -> CString -> CString -> Int -> Int -> IO Int32
c_write_time CString
time_str CString
tz Int
l Int
l2)
                    )
              Int32 -> Writer Builder
forall w. MonoidMap ByteString w => Int32 -> Writer w
writeBinaryInt32 Int32
converted
            ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error (ByteString -> [Char]
typeMismatchError ByteString
col_name)
        )
        Vector ClickhouseType
items

foreign import ccall unsafe "datetime.h convert_time" c_convert_time :: Int64 -> CString -> Int -> IO CString

foreign import ccall unsafe "datetime.h convert_time" c_convert_time64 :: Float -> CString -> Int -> IO CString

foreign import ccall unsafe "datetime.h parse_time" c_write_time :: CString -> CString -> Int -> Int -> IO Int32

foreign import ccall unsafe "datetime.h convert_time_from_int32" convert_time_from_int32 :: Int32 -> IO Int32

------------------------------------------------------------------------------------------------
readLowCardinality :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readLowCardinality :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readLowCardinality ServerInfo
_ Int
0 ByteString
_ = Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return ([ClickhouseType] -> Vector ClickhouseType
forall a. [a] -> Vector a
V.fromList [])
readLowCardinality ServerInfo
server_info Int
n ByteString
spec = do
  StateT Buffer IO Word64
readBinaryUInt64 --state prefix
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
  let inner :: ByteString
inner = Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
16) (Int -> ByteString -> ByteString
BS.drop Int
15 ByteString
spec)
  Word64
serialization_type <- StateT Buffer IO Word64
readBinaryUInt64
  -- Lowest bytes contains info about key type.
  let key_type :: Word64
key_type = Word64
serialization_type Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xf
  Word64
index_size <- StateT Buffer IO Word64
readBinaryUInt64
  -- Strip the 'Nullable' tag to avoid null map reading.
  Vector ClickhouseType
index <- ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readColumn ServerInfo
server_info (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
index_size) (ByteString -> ByteString
stripNullable ByteString
inner)
  StateT Buffer IO Word64
readBinaryUInt64 -- #keys
  Vector Int
keys <- case Word64
key_type of
    Word64
0 -> (Word8 -> Int) -> Vector Word8 -> Vector Int
forall a b. (a -> b) -> Vector a -> Vector b
V.map Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Vector Word8 -> Vector Int)
-> StateT Buffer IO (Vector Word8) -> StateT Buffer IO (Vector Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> StateT Buffer IO Word8 -> StateT Buffer IO (Vector Word8)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n StateT Buffer IO Word8
readBinaryUInt8
    Word64
1 -> (Word16 -> Int) -> Vector Word16 -> Vector Int
forall a b. (a -> b) -> Vector a -> Vector b
V.map Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Vector Word16 -> Vector Int)
-> StateT Buffer IO (Vector Word16)
-> StateT Buffer IO (Vector Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> StateT Buffer IO Word16 -> StateT Buffer IO (Vector Word16)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n StateT Buffer IO Word16
readBinaryUInt16
    Word64
2 -> (Word32 -> Int) -> Vector Word32 -> Vector Int
forall a b. (a -> b) -> Vector a -> Vector b
V.map Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Vector Word32 -> Vector Int)
-> StateT Buffer IO (Vector Word32)
-> StateT Buffer IO (Vector Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> StateT Buffer IO Word32 -> StateT Buffer IO (Vector Word32)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n StateT Buffer IO Word32
readBinaryUInt32
    Word64
3 -> (Word64 -> Int) -> Vector Word64 -> Vector Int
forall a b. (a -> b) -> Vector a -> Vector b
V.map Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Vector Word64 -> Vector Int)
-> StateT Buffer IO (Vector Word64)
-> StateT Buffer IO (Vector Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> StateT Buffer IO Word64 -> StateT Buffer IO (Vector Word64)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n StateT Buffer IO Word64
readBinaryUInt64
  if ByteString
"Nullable" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
inner
    then do
      let nullable :: Vector ClickhouseType
nullable = (Int -> ClickhouseType) -> Vector Int -> Vector ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Int
k -> if Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then ClickhouseType
CKNull else Vector ClickhouseType
index Vector ClickhouseType -> Int -> ClickhouseType
forall a. Vector a -> Int -> a
! Int
k) Vector Int
keys
      Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return Vector ClickhouseType
nullable
    else Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Vector ClickhouseType -> Reader (Vector ClickhouseType))
-> Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall a b. (a -> b) -> a -> b
$ (Int -> ClickhouseType) -> Vector Int -> Vector ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Vector ClickhouseType
index Vector ClickhouseType -> Int -> ClickhouseType
forall a. Vector a -> Int -> a
!) Vector Int
keys
  where
    stripNullable :: ByteString -> ByteString
    stripNullable :: ByteString -> ByteString
stripNullable ByteString
spec
      | ByteString
"Nullable" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec = Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
10) (Int -> ByteString -> ByteString
BS.drop Int
9 ByteString
spec)
      | Bool
otherwise = ByteString
spec
    l :: Int
l = ByteString -> Int
BS.length ByteString
spec

writeLowCardinality :: Context -> ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeLowCardinality :: Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeLowCardinality Context
ctx ByteString
col_name ByteString
spec Vector ClickhouseType
items = do
  let inner :: ByteString
inner = Int -> ByteString -> ByteString
BS.take (ByteString -> Int
BS.length ByteString
spec Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
16) (Int -> ByteString -> ByteString
BS.drop Int
15 ByteString
spec)
  (Vector Int
keys, Vector Int
index) <-
    if ByteString
"Nullable" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
inner
      then do
        --let null_inner_spec = BS.take (BS.length inner - 10) (BS.drop 9 spec)
        let hashedItem :: Vector Int
hashedItem = Bool -> Vector ClickhouseType -> Vector Int
hashItems Bool
True Vector ClickhouseType
items
        let key_by_index_element :: HashMap Int Int
key_by_index_element = (HashMap Int Int -> Int -> HashMap Int Int)
-> HashMap Int Int -> Vector Int -> HashMap Int Int
forall a b. (a -> b -> a) -> a -> Vector b -> a
V.foldl' HashMap Int Int -> Int -> HashMap Int Int
forall a. (Hashable a, Eq a) => HashMap a Int -> a -> HashMap a Int
insertKeys HashMap Int Int
forall k v. HashMap k v
Map.empty Vector Int
hashedItem
        let keys :: Vector Int
keys = (Int -> Int) -> Vector Int -> Vector Int
forall a b. (a -> b) -> Vector a -> Vector b
V.map (\Int
k -> HashMap Int Int
key_by_index_element HashMap Int Int -> Int -> Int
forall k v.
(Eq k, Hashable k, HasCallStack) =>
HashMap k v -> k -> v
Map.! Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Vector Int
hashedItem
        -- First element is NULL if column is nullable
        let index :: Vector Int
index = [Int] -> Vector Int
forall a. [a] -> Vector a
V.fromList ([Int] -> Vector Int) -> [Int] -> Vector Int
forall a b. (a -> b) -> a -> b
$ Int
0 Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: (HashMap Int Int -> [Int]
forall k v. HashMap k v -> [k]
Map.keys (HashMap Int Int -> [Int]) -> HashMap Int Int -> [Int]
forall a b. (a -> b) -> a -> b
$ HashMap Int Int
key_by_index_element)
        (Vector Int, Vector Int)
-> WriterT Builder IO (Vector Int, Vector Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Vector Int
keys, Vector Int
index)
      else do
        let hashedItem :: Vector Int
hashedItem = Bool -> Vector ClickhouseType -> Vector Int
hashItems Bool
False Vector ClickhouseType
items
        let key_by_index_element :: HashMap Int Int
key_by_index_element = (HashMap Int Int -> Int -> HashMap Int Int)
-> HashMap Int Int -> Vector Int -> HashMap Int Int
forall a b. (a -> b -> a) -> a -> Vector b -> a
V.foldl' HashMap Int Int -> Int -> HashMap Int Int
forall a. (Hashable a, Eq a) => HashMap a Int -> a -> HashMap a Int
insertKeys HashMap Int Int
forall k v. HashMap k v
Map.empty Vector Int
hashedItem
        let keys :: Vector Int
keys = (Int -> Int) -> Vector Int -> Vector Int
forall a b. (a -> b) -> Vector a -> Vector b
V.map (HashMap Int Int
key_by_index_element HashMap Int Int -> Int -> Int
forall k v.
(Eq k, Hashable k, HasCallStack) =>
HashMap k v -> k -> v
Map.!) Vector Int
hashedItem
        let index :: Vector Int
index = [Int] -> Vector Int
forall a. [a] -> Vector a
V.fromList ([Int] -> Vector Int) -> [Int] -> Vector Int
forall a b. (a -> b) -> a -> b
$ HashMap Int Int -> [Int]
forall k v. HashMap k v -> [k]
Map.keys (HashMap Int Int -> [Int]) -> HashMap Int Int -> [Int]
forall a b. (a -> b) -> a -> b
$ HashMap Int Int
key_by_index_element
        (Vector Int, Vector Int)
-> WriterT Builder IO (Vector Int, Vector Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Vector Int
keys, Vector Int
index)
  if Vector Int -> Int
forall a. Vector a -> Int
V.length Vector Int
index Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
    then () -> Writer Builder
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    else do
      let int_type :: Int64
int_type = Double -> Int64
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double -> Int64) -> Double -> Int64
forall a b. (a -> b) -> a -> b
$ Double -> Double -> Double
forall a. Floating a => a -> a -> a
logBase Double
2 (Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Double) -> Int -> Double
forall a b. (a -> b) -> a -> b
$ Vector Int -> Int
forall a. Vector a -> Int
V.length Vector Int
index) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
8 :: Int64
      let has_additional_keys_bit :: Int64
has_additional_keys_bit = Int64
1 Int64 -> Int -> Int64
forall a. Bits a => a -> Int -> a
`shift` Int
9
      let need_update_dictionary :: Int64
need_update_dictionary = Int64
1 Int64 -> Int -> Int64
forall a. Bits a => a -> Int -> a
`shift` Int
10
      let serialization_type :: Int64
serialization_type =
            Int64
has_additional_keys_bit
              Int64 -> Int64 -> Int64
forall a. Bits a => a -> a -> a
.|. Int64
need_update_dictionary
              Int64 -> Int64 -> Int64
forall a. Bits a => a -> a -> a
.|. Int64
int_type
      let nullsInner :: ByteString
nullsInner =
            if ByteString
"Nullable" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
inner
              then Int -> ByteString -> ByteString
BS.take (ByteString -> Int
BS.length ByteString
inner Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
10) (Int -> ByteString -> ByteString
BS.drop Int
9 ByteString
spec)
              else ByteString
inner
      Word64 -> Writer Builder
forall w. MonoidMap ByteString w => Word64 -> Writer w
writeBinaryUInt64 Word64
1 --state prefix
      Int64 -> Writer Builder
forall w. MonoidMap ByteString w => Int64 -> Writer w
writeBinaryInt64 Int64
serialization_type
      Int64 -> Writer Builder
forall w. MonoidMap ByteString w => Int64 -> Writer w
writeBinaryInt64 (Int64 -> Writer Builder) -> Int64 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int64) -> Int -> Int64
forall a b. (a -> b) -> a -> b
$ Vector Int -> Int
forall a. Vector a -> Int
V.length Vector Int
index
      Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeColumn Context
ctx ByteString
col_name ByteString
nullsInner Vector ClickhouseType
items
      Int64 -> Writer Builder
forall w. MonoidMap ByteString w => Int64 -> Writer w
writeBinaryInt64 (Int64 -> Writer Builder) -> Int64 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int64) -> Int -> Int64
forall a b. (a -> b) -> a -> b
$ Vector ClickhouseType -> Int
forall a. Vector a -> Int
V.length Vector ClickhouseType
items
      case Int64
int_type of
        Int64
0 -> (Int -> Writer Builder) -> Vector Int -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_ (Word8 -> Writer Builder
forall w. MonoidMap ByteString w => Word8 -> Writer w
writeBinaryUInt8 (Word8 -> Writer Builder)
-> (Int -> Word8) -> Int -> Writer Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral) Vector Int
keys
        Int64
1 -> (Int -> Writer Builder) -> Vector Int -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_ (Word16 -> Writer Builder
forall w. MonoidMap ByteString w => Word16 -> Writer w
writeBinaryUInt16 (Word16 -> Writer Builder)
-> (Int -> Word16) -> Int -> Writer Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral) Vector Int
keys
        Int64
2 -> (Int -> Writer Builder) -> Vector Int -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_ (Word32 -> Writer Builder
forall w. MonoidMap ByteString w => Word32 -> Writer w
writeBinaryUInt32 (Word32 -> Writer Builder)
-> (Int -> Word32) -> Int -> Writer Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral) Vector Int
keys
        Int64
3 -> (Int -> Writer Builder) -> Vector Int -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_ (Word64 -> Writer Builder
forall w. MonoidMap ByteString w => Word64 -> Writer w
writeBinaryUInt64 (Word64 -> Writer Builder)
-> (Int -> Word64) -> Int -> Writer Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral) Vector Int
keys
  where
    insertKeys :: (Hashable a, Eq a) => Map.HashMap a Int -> a -> Map.HashMap a Int
    insertKeys :: HashMap a Int -> a -> HashMap a Int
insertKeys HashMap a Int
m a
a = if a -> HashMap a Int -> Bool
forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
Map.member a
a HashMap a Int
m then HashMap a Int
m else a -> Int -> HashMap a Int -> HashMap a Int
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
Map.insert a
a (HashMap a Int -> Int
forall k v. HashMap k v -> Int
Map.size HashMap a Int
m) HashMap a Int
m

    hashItems :: Bool -> Vector ClickhouseType -> Vector Int
    hashItems :: Bool -> Vector ClickhouseType -> Vector Int
hashItems Bool
isNullable Vector ClickhouseType
items =
      (ClickhouseType -> Int) -> Vector ClickhouseType -> Vector Int
forall a b. (a -> b) -> Vector a -> Vector b
V.map
        ( \case
            CKInt16 Int16
x -> Int16 -> Int
forall a. Hashable a => a -> Int
hash Int16
x
            CKInt8 Int8
x -> Int8 -> Int
forall a. Hashable a => a -> Int
hash Int8
x
            CKInt32 Int32
x -> Int32 -> Int
forall a. Hashable a => a -> Int
hash Int32
x
            CKInt64 Int64
x -> Int64 -> Int
forall a. Hashable a => a -> Int
hash Int64
x
            CKUInt8 Word8
x -> Word8 -> Int
forall a. Hashable a => a -> Int
hash Word8
x
            CKUInt16 Word16
x -> Word16 -> Int
forall a. Hashable a => a -> Int
hash Word16
x
            CKUInt32 Word32
x -> Word32 -> Int
forall a. Hashable a => a -> Int
hash Word32
x
            CKUInt64 Word64
x -> Word64 -> Int
forall a. Hashable a => a -> Int
hash Word64
x
            CKString ByteString
str -> ByteString -> Int
forall a. Hashable a => a -> Int
hash ByteString
str
            ClickhouseType
CKNull ->
              if Bool
isNullable
                then Int -> Int
forall a. Hashable a => a -> Int
hash (Int
0 :: Int)
                else [Char] -> Int
forall a. HasCallStack => [Char] -> a
error ([Char] -> Int) -> [Char] -> Int
forall a b. (a -> b) -> a -> b
$ ByteString -> [Char]
typeMismatchError ByteString
col_name
            ClickhouseType
_ -> [Char] -> Int
forall a. HasCallStack => [Char] -> a
error ([Char] -> Int) -> [Char] -> Int
forall a b. (a -> b) -> a -> b
$ ByteString -> [Char]
typeMismatchError ByteString
col_name
        )
        Vector ClickhouseType
items

---------------------------------------------------------------------------------------------------------------------------------
{-
          Informal description (in terms of regular expression form) for this config:
          (\Null | \SOH)^{n_rows}
          \Null means null and \SOH which equals 1 means not null. The `|` in the middle means or.
-}
readNullable :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readNullable :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readNullable ServerInfo
server_info Int
n_rows ByteString
spec = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
  let cktype :: ByteString
cktype = Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
10) (Int -> ByteString -> ByteString
BS.drop Int
9 ByteString
spec) -- Read Clickhouse type inside the bracket after the 'Nullable' spec.
  Vector Word8
config <- Int -> StateT Buffer IO (Vector Word8)
readNullableConfig Int
n_rows
  Vector ClickhouseType
items <- ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readColumn ServerInfo
server_info Int
n_rows ByteString
cktype
  let result :: Vector ClickhouseType
result = Int -> (Int -> ClickhouseType) -> Vector ClickhouseType
forall a. Int -> (Int -> a) -> Vector a
V.generate Int
n_rows (\Int
i -> if Vector Word8
config Vector Word8 -> Int -> Word8
forall a. Vector a -> Int -> a
! Int
i Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
1 then ClickhouseType
CKNull else Vector ClickhouseType
items Vector ClickhouseType -> Int -> ClickhouseType
forall a. Vector a -> Int -> a
! Int
i)
  Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return Vector ClickhouseType
result
  where
    readNullableConfig :: Int -> Reader (Vector Word8)
    readNullableConfig :: Int -> StateT Buffer IO (Vector Word8)
readNullableConfig Int
n_rows = do
      ByteString
config <- Int -> StateT Buffer IO ByteString
readBinaryStrWithLength Int
n_rows
      (Vector Word8 -> StateT Buffer IO (Vector Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return (Vector Word8 -> StateT Buffer IO (Vector Word8))
-> (ByteString -> Vector Word8)
-> ByteString
-> StateT Buffer IO (Vector Word8)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> Vector Word8
forall a. [a] -> Vector a
V.fromList ([Word8] -> Vector Word8)
-> (ByteString -> [Word8]) -> ByteString -> Vector Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
BS.unpack) ByteString
config

writeNullable :: Context -> ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeNullable :: Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeNullable Context
ctx ByteString
col_name ByteString
spec Vector ClickhouseType
items = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
  let inner :: ByteString
inner = Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
10) (Int -> ByteString -> ByteString
BS.drop Int
9 ByteString
spec)
  Vector ClickhouseType -> Writer Builder
writeNullsMap Vector ClickhouseType
items
  Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeColumn Context
ctx ByteString
col_name ByteString
inner Vector ClickhouseType
items
  where
    writeNullsMap :: Vector ClickhouseType -> Writer Builder
    writeNullsMap :: Vector ClickhouseType -> Writer Builder
writeNullsMap =
      (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
        ( \case
            ClickhouseType
CKNull -> Int8 -> Writer Builder
forall w. MonoidMap ByteString w => Int8 -> Writer w
writeBinaryInt8 Int8
1
            ClickhouseType
_ -> Int8 -> Writer Builder
forall w. MonoidMap ByteString w => Int8 -> Writer w
writeBinaryInt8 Int8
0
        )

---------------------------------------------------------------------------------------------------------------------------------
{-
  Format:
  "
     One element of array of arrays can be represented as tree:
      (0 depth)          [[3, 4], [5, 6]]
                        |               |
      (1 depth)      [3, 4]           [5, 6]
                    |    |           |    |
      (leaf)        3     4          5     6
      Offsets (sizes) written in breadth-first search order. In example above
      following sequence of offset will be written: 4 -> 2 -> 4
      1) size of whole array: 4
      2) size of array 1 in depth=1: 2
      3) size of array 2 plus size of all array before in depth=1: 2 + 2 = 4
      After sizes info comes flatten data: 3 -> 4 -> 5 -> 6
  "
      Quoted from https://github.com/mymarilyn/clickhouse-driver/blob/master/clickhouse_driver/columns/arraycolumn.py

Here we don't implement in the form of BFS; instead, we use bottom up method:
First off, we compute the array of integer in which elements represent the size of subarrays (we call them spec arrays)
, where the function `readArraySpec`, `cut`, and `intervalize` do their jobs.
Second, we place the array of atomic elements (or flatten data) at the last position.
Then we cut the array of atomic elements according to the last spec array and form nested a nested array.
Finally we pop out the last spec array.
Repeat this process until all spec arrays are gone.

For example:
The target array is [[3, 4], [5, 6]]
The array on the right hand side of `|` is array of atomic elements.
The algorithm would be like this:
[2] [2,2] | [3,4,5,6]
-> [2] | [[3,4],[5,6]]
-> [[3,4],[5,6]]

For another example:
   target [[["Alex","Bob"], ["John"]],[["Jane"],["Steven","Mike","Sarah"]],[["Hello","world"]]]
   [3] [2,2,1] [2,1,1,3,2] | ["Alex","Bob","John","Jane","Steven","Mike","Sarah","Hello","world"]
-> [3] [2,2,1] | [["Alex","Bob"],["John"],["Jane"],["Steven","Mike","Sarah"],["Hello","world"]]
-> [3] | [[["Alex","Bob"],["John"]],[["Jane"],["Steven","Mike","Sarah"]],[["Hello","world"]]]
-> [[["Alex","Bob"],["John"]],[["Jane"],["Steven","Mike","Sarah"]],[["Hello","world"]]]

-}
readArray :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readArray :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readArray ServerInfo
server_info Int
n_rows ByteString
spec = do
  (ByteString
lastSpec, Vector Word64
x : [Vector Word64]
xs) <- ByteString
-> [Vector Word64] -> Reader (ByteString, [Vector Word64])
genSpecs ByteString
spec [[Word64] -> Vector Word64
forall a. [a] -> Vector a
V.fromList [Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n_rows]]
  --  lastSpec which is not `Array`
  --  x:xs is the
  let numElem :: Int
numElem = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int) -> Word64 -> Int
forall a b. (a -> b) -> a -> b
$ Vector Word64 -> Word64
forall a. Num a => Vector a -> a
V.sum Vector Word64
x -- number of elements in the nested array.
  Vector ClickhouseType
elems <- ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readColumn ServerInfo
server_info Int
numElem ByteString
lastSpec
  let result' :: Vector ClickhouseType
result' = (Vector ClickhouseType -> Vector Word64 -> Vector ClickhouseType)
-> Vector ClickhouseType
-> [Vector Word64]
-> Vector ClickhouseType
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Vector ClickhouseType -> Vector Word64 -> Vector ClickhouseType
combine Vector ClickhouseType
elems (Vector Word64
x Vector Word64 -> [Vector Word64] -> [Vector Word64]
forall a. a -> [a] -> [a]
: [Vector Word64]
xs)
  let CKArray Vector ClickhouseType
arr = Vector ClickhouseType
result' Vector ClickhouseType -> Int -> ClickhouseType
forall a. Vector a -> Int -> a
! Int
0
  Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return Vector ClickhouseType
arr
  where
    combine :: Vector ClickhouseType -> Vector Word64 -> Vector ClickhouseType
    combine :: Vector ClickhouseType -> Vector Word64 -> Vector ClickhouseType
combine Vector ClickhouseType
elems Vector Word64
config =
      let intervals :: Vector (Int, Int)
intervals = Vector Int -> Vector (Int, Int)
intervalize (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int) -> Vector Word64 -> Vector Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Vector Word64
config)
          cut :: (Int, Int)->ClickhouseType
          cut :: (Int, Int) -> ClickhouseType
cut (Int
a, Int
b) = Vector ClickhouseType -> ClickhouseType
CKArray (Vector ClickhouseType -> ClickhouseType)
-> Vector ClickhouseType -> ClickhouseType
forall a b. (a -> b) -> a -> b
$ Int -> Vector ClickhouseType -> Vector ClickhouseType
forall a. Int -> Vector a -> Vector a
V.take Int
b (Int -> Vector ClickhouseType -> Vector ClickhouseType
forall a. Int -> Vector a -> Vector a
V.drop Int
a Vector ClickhouseType
elems)
          embed :: Vector ClickhouseType
embed = (\(Int
l, Int
r) -> (Int, Int) -> ClickhouseType
cut (Int
l, Int
r Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) ((Int, Int) -> ClickhouseType)
-> Vector (Int, Int) -> Vector ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Vector (Int, Int)
intervals
      in Vector ClickhouseType
embed

    intervalize :: Vector Int -> Vector (Int, Int)
    intervalize :: Vector Int -> Vector (Int, Int)
intervalize Vector Int
vec = Int -> Vector (Int, Int) -> Vector (Int, Int)
forall a. Int -> Vector a -> Vector a
V.drop Int
1 (Vector (Int, Int) -> Vector (Int, Int))
-> Vector (Int, Int) -> Vector (Int, Int)
forall a b. (a -> b) -> a -> b
$ ((Int, Int) -> Int -> (Int, Int))
-> (Int, Int) -> Vector Int -> Vector (Int, Int)
forall a b. (a -> b -> a) -> a -> Vector b -> Vector a
V.scanl' (\(Int
_, Int
b) Int
v -> (Int
b Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1, Int
v Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
b)) (-Int
1, -Int
1) Vector Int
vec -- drop the first tuple (-1,-1)

readArraySpec :: Vector Word64 -> Reader (Vector Word64)
readArraySpec :: Vector Word64 -> StateT Buffer IO (Vector Word64)
readArraySpec Vector Word64
sizeArr = do
  let arrSum :: Int
arrSum = (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int)
-> (Vector Word64 -> Word64) -> Vector Word64 -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Vector Word64 -> Word64
forall a. Num a => Vector a -> a
V.sum) Vector Word64
sizeArr
  Vector Word64
offsets <- Int -> StateT Buffer IO Word64 -> StateT Buffer IO (Vector Word64)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
arrSum StateT Buffer IO Word64
readBinaryUInt64
  let offsets' :: Vector Word64
offsets' = Word64 -> Vector Word64 -> Vector Word64
forall a. a -> Vector a -> Vector a
V.cons Word64
0 (Int -> Vector Word64 -> Vector Word64
forall a. Int -> Vector a -> Vector a
V.take (Int
arrSum Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Vector Word64
offsets)
  let sizes :: Vector Word64
sizes = (Word64 -> Word64 -> Word64)
-> Vector Word64 -> Vector Word64 -> Vector Word64
forall a b c. (a -> b -> c) -> Vector a -> Vector b -> Vector c
V.zipWith (-) Vector Word64
offsets Vector Word64
offsets'
  Vector Word64 -> StateT Buffer IO (Vector Word64)
forall (m :: * -> *) a. Monad m => a -> m a
return Vector Word64
sizes

genSpecs :: ByteString -> [Vector Word64] -> Reader (ByteString, [Vector Word64])
genSpecs :: ByteString
-> [Vector Word64] -> Reader (ByteString, [Vector Word64])
genSpecs ByteString
spec rest :: [Vector Word64]
rest@(Vector Word64
x : [Vector Word64]
_) = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
  let cktype :: ByteString
cktype = Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
7) (Int -> ByteString -> ByteString
BS.drop Int
6 ByteString
spec)
  if ByteString
"Array" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
    then do
      Vector Word64
next <- Vector Word64 -> StateT Buffer IO (Vector Word64)
readArraySpec Vector Word64
x
      ByteString
-> [Vector Word64] -> Reader (ByteString, [Vector Word64])
genSpecs ByteString
cktype (Vector Word64
next Vector Word64 -> [Vector Word64] -> [Vector Word64]
forall a. a -> [a] -> [a]
: [Vector Word64]
rest)
    else (ByteString, [Vector Word64])
-> Reader (ByteString, [Vector Word64])
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString
spec, [Vector Word64]
rest)

writeArray :: Context -> ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeArray :: Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeArray Context
ctx ByteString
col_name ByteString
spec Vector ClickhouseType
items = do
  let lens :: Vector Int
lens =
        (Int -> ClickhouseType -> Int)
-> Int -> Vector ClickhouseType -> Vector Int
forall a b. (a -> b -> a) -> a -> Vector b -> Vector a
V.scanl'
          ( \Int
total ->
              ( \case
                  (CKArray Vector ClickhouseType
xs) -> Int
total Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Vector ClickhouseType -> Int
forall a. Vector a -> Int
V.length Vector ClickhouseType
xs
                  ClickhouseType
x ->
                    [Char] -> Int
forall a. HasCallStack => [Char] -> a
error ([Char] -> Int) -> [Char] -> Int
forall a b. (a -> b) -> a -> b
$
                      [Char]
"unexpected type in the column: "
                        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ByteString -> [Char]
forall a. Show a => a -> [Char]
show ByteString
col_name
                        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" with data"
                        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ClickhouseType -> [Char]
forall a. Show a => a -> [Char]
show ClickhouseType
x
              )
          )
          Int
0
          Vector ClickhouseType
items
  (Int -> Writer Builder) -> Vector Int -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_ (Int64 -> Writer Builder
forall w. MonoidMap ByteString w => Int64 -> Writer w
writeBinaryInt64 (Int64 -> Writer Builder)
-> (Int -> Int64) -> Int -> Writer Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral) (Int -> Vector Int -> Vector Int
forall a. Int -> Vector a -> Vector a
V.drop Int
1 Vector Int
lens)
  let innerSpec :: ByteString
innerSpec = Int -> ByteString -> ByteString
BS.take (ByteString -> Int
BS.length ByteString
spec Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
7) (Int -> ByteString -> ByteString
BS.drop Int
6 ByteString
spec)
  let innerVector :: Vector (Vector ClickhouseType)
innerVector = (ClickhouseType -> Vector ClickhouseType)
-> Vector ClickhouseType -> Vector (Vector ClickhouseType)
forall a b. (a -> b) -> Vector a -> Vector b
V.map (\case CKArray Vector ClickhouseType
xs -> Vector ClickhouseType
xs) Vector ClickhouseType
items
  let flattenVector :: Vector ClickhouseType
flattenVector =
        Vector (Vector ClickhouseType)
innerVector Vector (Vector ClickhouseType)
-> (Vector ClickhouseType -> Vector ClickhouseType)
-> Vector ClickhouseType
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Vector ClickhouseType
v -> do Vector ClickhouseType
v
  Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeColumn Context
ctx ByteString
col_name ByteString
innerSpec Vector ClickhouseType
flattenVector

--------------------------------------------------------------------------------------
readTuple :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readTuple :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readTuple ServerInfo
server_info Int
n_rows ByteString
spec = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
  let innerSpecString :: ByteString
innerSpecString = Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
7) (Int -> ByteString -> ByteString
BS.drop Int
6 ByteString
spec) -- Tuple(...) the dots represent innerSpecString
  let arr :: Vector ByteString
arr = [ByteString] -> Vector ByteString
forall a. [a] -> Vector a
V.fromList (ByteString -> [ByteString]
getSpecs ByteString
innerSpecString)
  Vector (Vector ClickhouseType)
datas <- (ByteString -> Reader (Vector ClickhouseType))
-> Vector ByteString
-> StateT Buffer IO (Vector (Vector ClickhouseType))
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Vector a -> m (Vector b)
V.mapM (ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readColumn ServerInfo
server_info Int
n_rows) Vector ByteString
arr
  let transposed :: Vector (Vector ClickhouseType)
transposed = Vector (Vector ClickhouseType) -> Vector (Vector ClickhouseType)
transpose Vector (Vector ClickhouseType)
datas
  Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Vector ClickhouseType -> Reader (Vector ClickhouseType))
-> Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall a b. (a -> b) -> a -> b
$ Vector ClickhouseType -> ClickhouseType
CKTuple (Vector ClickhouseType -> ClickhouseType)
-> Vector (Vector ClickhouseType) -> Vector ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Vector (Vector ClickhouseType)
transposed

writeTuple :: Context -> ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeTuple :: Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeTuple Context
ctx ByteString
col_name ByteString
spec Vector ClickhouseType
items = do
  let inner :: ByteString
inner = Int -> ByteString -> ByteString
BS.take (ByteString -> Int
BS.length ByteString
spec Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
7) (Int -> ByteString -> ByteString
BS.drop Int
6 ByteString
spec)
  let spec_arr :: Vector ByteString
spec_arr = [ByteString] -> Vector ByteString
forall a. [a] -> Vector a
V.fromList ([ByteString] -> Vector ByteString)
-> [ByteString] -> Vector ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> [ByteString]
getSpecs ByteString
inner
  let transposed :: Vector (Vector ClickhouseType)
transposed =
        Vector (Vector ClickhouseType) -> Vector (Vector ClickhouseType)
transpose
          ( (ClickhouseType -> Vector ClickhouseType)
-> Vector ClickhouseType -> Vector (Vector ClickhouseType)
forall a b. (a -> b) -> Vector a -> Vector b
V.map
              ( \case
                  CKTuple Vector ClickhouseType
tupleVec -> Vector ClickhouseType
tupleVec
                  ClickhouseType
other ->
                    [Char] -> Vector ClickhouseType
forall a. HasCallStack => [Char] -> a
error
                      ( [Char]
"expected type: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ClickhouseType -> [Char]
forall a. Show a => a -> [Char]
show ClickhouseType
other
                          [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"in the column:"
                          [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ByteString -> [Char]
forall a. Show a => a -> [Char]
show ByteString
col_name
                      )
              )
              Vector ClickhouseType
items
          )
  if Vector ByteString -> Int
forall a. Vector a -> Int
V.length Vector ByteString
spec_arr Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Vector (Vector ClickhouseType) -> Int
forall a. Vector a -> Int
V.length Vector (Vector ClickhouseType)
transposed
    then
      [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error ([Char] -> Writer Builder) -> [Char] -> Writer Builder
forall a b. (a -> b) -> a -> b
$
        [Char]
"length of the given array does not match, column name = "
          [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ByteString -> [Char]
forall a. Show a => a -> [Char]
show ByteString
col_name
    else do
      (ByteString -> Vector ClickhouseType -> Writer Builder)
-> Vector ByteString
-> Vector (Vector ClickhouseType)
-> Writer Builder
forall (m :: * -> *) a b c.
Monad m =>
(a -> b -> m c) -> Vector a -> Vector b -> m ()
V.zipWithM_ (Context
-> ByteString
-> ByteString
-> Vector ClickhouseType
-> Writer Builder
writeColumn Context
ctx ByteString
col_name) Vector ByteString
spec_arr Vector (Vector ClickhouseType)
transposed

--------------------------------------------------------------------------------------
readEnum :: Int -> ByteString -> Reader (Vector ClickhouseType)
readEnum :: Int -> ByteString -> Reader (Vector ClickhouseType)
readEnum Int
n_rows ByteString
spec = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
      innerSpec :: ByteString
innerSpec =
        if ByteString
"Enum8" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
          then Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
7) (Int -> ByteString -> ByteString
BS.drop Int
6 ByteString
spec)
          else Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
8) (Int -> ByteString -> ByteString
BS.drop Int
7 ByteString
spec) -- otherwise it is `Enum16`
      pres_pecs :: [ByteString]
pres_pecs = ByteString -> [ByteString]
getSpecs ByteString
innerSpec
      specs :: [(Int, ByteString)]
specs =
        (\(ByteString
name, Just (Int
n, ByteString
_)) -> (Int
n, ByteString
name))
          ((ByteString, Maybe (Int, ByteString)) -> (Int, ByteString))
-> [(ByteString, Maybe (Int, ByteString))] -> [(Int, ByteString)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((\[ByteString
x, ByteString
y] -> (ByteString
x, ByteString -> Maybe (Int, ByteString)
readInt ByteString
y)) ([ByteString] -> (ByteString, Maybe (Int, ByteString)))
-> (ByteString -> [ByteString])
-> ByteString
-> (ByteString, Maybe (Int, ByteString))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8 -> Bool) -> ByteString -> [ByteString]
BS.splitWith (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== EQUAL) <$> pres_pecs) --61 means '='
      specsMap :: HashMap Int ByteString
specsMap = [(Int, ByteString)] -> HashMap Int ByteString
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
Map.fromList [(Int, ByteString)]
specs
  if ByteString
"Enum8" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
    then do
      Vector Int8
values <- Int -> StateT Buffer IO Int8 -> StateT Buffer IO (Vector Int8)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows StateT Buffer IO Int8
readBinaryInt8
      Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Vector ClickhouseType -> Reader (Vector ClickhouseType))
-> Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall a b. (a -> b) -> a -> b
$ ByteString -> ClickhouseType
CKString (ByteString -> ClickhouseType)
-> (Int8 -> ByteString) -> Int8 -> ClickhouseType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HashMap Int ByteString
specsMap HashMap Int ByteString -> Int -> ByteString
forall k v.
(Eq k, Hashable k, HasCallStack) =>
HashMap k v -> k -> v
Map.!) (Int -> ByteString) -> (Int8 -> Int) -> Int8 -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int8 -> ClickhouseType) -> Vector Int8 -> Vector ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Vector Int8
values
    else do
      Vector Int16
values <- Int -> StateT Buffer IO Int16 -> StateT Buffer IO (Vector Int16)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows StateT Buffer IO Int16
readBinaryInt16
      Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Vector ClickhouseType -> Reader (Vector ClickhouseType))
-> Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall a b. (a -> b) -> a -> b
$ ByteString -> ClickhouseType
CKString (ByteString -> ClickhouseType)
-> (Int16 -> ByteString) -> Int16 -> ClickhouseType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HashMap Int ByteString
specsMap HashMap Int ByteString -> Int -> ByteString
forall k v.
(Eq k, Hashable k, HasCallStack) =>
HashMap k v -> k -> v
Map.!) (Int -> ByteString) -> (Int16 -> Int) -> Int16 -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int16 -> ClickhouseType) -> Vector Int16 -> Vector ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Vector Int16
values

writeEnum :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeEnum :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeEnum ByteString
col_name ByteString
spec Vector ClickhouseType
items = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
      innerSpec :: ByteString
innerSpec =
        if ByteString
"Enum8" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
          then Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
7) (Int -> ByteString -> ByteString
BS.drop Int
6 ByteString
spec)
          else Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
8) (Int -> ByteString -> ByteString
BS.drop Int
7 ByteString
spec)
      pres_pecs :: [ByteString]
pres_pecs = ByteString -> [ByteString]
getSpecs ByteString
innerSpec
      specs :: [(ByteString, Int)]
specs =
        (\(ByteString
name, Just (Int
n, ByteString
_)) -> (ByteString
name, Int
n))
          ((ByteString, Maybe (Int, ByteString)) -> (ByteString, Int))
-> [(ByteString, Maybe (Int, ByteString))] -> [(ByteString, Int)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((\[ByteString
x, ByteString
y] -> (ByteString
x, ByteString -> Maybe (Int, ByteString)
readInt ByteString
y)) ([ByteString] -> (ByteString, Maybe (Int, ByteString)))
-> (ByteString -> [ByteString])
-> ByteString
-> (ByteString, Maybe (Int, ByteString))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8 -> Bool) -> ByteString -> [ByteString]
BS.splitWith (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== EQUAL) . BS.filter (/= QUOTE) <$> pres_pecs) --61 is '='
      specsMap :: HashMap ByteString Int
specsMap = [(ByteString, Int)] -> HashMap ByteString Int
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
Map.fromList [(ByteString, Int)]
specs
  (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
    ( \case
        CKString ByteString
str ->
          ( if ByteString
"Enum8" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
              then Int8 -> Writer Builder
forall w. MonoidMap ByteString w => Int8 -> Writer w
writeBinaryInt8 (Int8 -> Writer Builder) -> Int8 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Int -> Int8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int8) -> Int -> Int8
forall a b. (a -> b) -> a -> b
$ HashMap ByteString Int
specsMap HashMap ByteString Int -> ByteString -> Int
forall k v.
(Eq k, Hashable k, HasCallStack) =>
HashMap k v -> k -> v
Map.! ByteString
str
              else Int16 -> Writer Builder
forall w. MonoidMap ByteString w => Int16 -> Writer w
writeBinaryInt16 (Int16 -> Writer Builder) -> Int16 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Int -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int16) -> Int -> Int16
forall a b. (a -> b) -> a -> b
$ HashMap ByteString Int
specsMap HashMap ByteString Int -> ByteString -> Int
forall k v.
(Eq k, Hashable k, HasCallStack) =>
HashMap k v -> k -> v
Map.! ByteString
str
          )
        ClickhouseType
CKNull ->
          if ByteString
"Enum8" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
            then Int8 -> Writer Builder
forall w. MonoidMap ByteString w => Int8 -> Writer w
writeBinaryInt8 Int8
0
            else Int16 -> Writer Builder
forall w. MonoidMap ByteString w => Int16 -> Writer w
writeBinaryInt16 Int16
0
        ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error ([Char] -> Writer Builder) -> [Char] -> Writer Builder
forall a b. (a -> b) -> a -> b
$ ByteString -> [Char]
typeMismatchError ByteString
col_name
    )
    Vector ClickhouseType
items

----------------------------------------------------------------------
readDate :: Int -> Reader (Vector ClickhouseType)
readDate :: Int -> Reader (Vector ClickhouseType)
readDate Int
n_rows = do
  let epoch_start :: Day
epoch_start = Integer -> Int -> Int -> Day
fromGregorian Integer
1970 Int
1 Int
1
  Vector Word16
days <- Int -> StateT Buffer IO Word16 -> StateT Buffer IO (Vector Word16)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows StateT Buffer IO Word16
readBinaryUInt16
  let dates :: Vector Day
dates = (Word16 -> Day) -> Vector Word16 -> Vector Day
forall a b. (a -> b) -> Vector a -> Vector b
V.map (\Word16
x -> Integer -> Day -> Day
addDays (Word16 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
x) Day
epoch_start) Vector Word16
days
      toTriple :: Vector (Integer, Int, Int)
toTriple = (Day -> (Integer, Int, Int))
-> Vector Day -> Vector (Integer, Int, Int)
forall a b. (a -> b) -> Vector a -> Vector b
V.map Day -> (Integer, Int, Int)
toGregorian Vector Day
dates
      toCK :: Vector ClickhouseType
toCK = ((Integer, Int, Int) -> ClickhouseType)
-> Vector (Integer, Int, Int) -> Vector ClickhouseType
forall a b. (a -> b) -> Vector a -> Vector b
V.map (\(Integer
y, Int
m, Int
d) -> Integer -> Int -> Int -> ClickhouseType
CKDate Integer
y Int
m Int
d) Vector (Integer, Int, Int)
toTriple
  Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return Vector ClickhouseType
toCK

writeDate :: ByteString -> Vector ClickhouseType -> Writer Builder
writeDate :: ByteString -> Vector ClickhouseType -> Writer Builder
writeDate ByteString
col_name Vector ClickhouseType
items = do
  let epoch_start :: Day
epoch_start = Integer -> Int -> Int -> Day
fromGregorian Integer
1970 Int
1 Int
1
  let serialize :: Vector Integer
serialize =
        (ClickhouseType -> Integer)
-> Vector ClickhouseType -> Vector Integer
forall a b. (a -> b) -> Vector a -> Vector b
V.map
          ( \case
              CKDate Integer
y Int
m Int
d -> Day -> Day -> Integer
diffDays (Integer -> Int -> Int -> Day
fromGregorian Integer
y Int
m Int
d) Day
epoch_start
              ClickhouseType
_ ->
                [Char] -> Integer
forall a. HasCallStack => [Char] -> a
error ([Char] -> Integer) -> [Char] -> Integer
forall a b. (a -> b) -> a -> b
$
                  [Char]
"unexpected type in the column: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ByteString -> [Char]
forall a. Show a => a -> [Char]
show ByteString
col_name
                    [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" whose type should be Date"
          )
          Vector ClickhouseType
items
  (Integer -> Writer Builder) -> Vector Integer -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_ (Int16 -> Writer Builder
forall w. MonoidMap ByteString w => Int16 -> Writer w
writeBinaryInt16 (Int16 -> Writer Builder)
-> (Integer -> Int16) -> Integer -> Writer Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral) Vector Integer
serialize

--------------------------------------------------------------------------------------
readDecimal :: Int -> ByteString -> Reader (Vector ClickhouseType)
readDecimal :: Int -> ByteString -> Reader (Vector ClickhouseType)
readDecimal Int
n_rows ByteString
spec = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
  let inner_spec :: [ByteString]
inner_spec = ByteString -> [ByteString]
getSpecs (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
9) (Int -> ByteString -> ByteString
BS.drop Int
8 ByteString
spec)
  let (Int -> Reader (Vector ClickhouseType)
specific, Just (Int
scale, ByteString
_)) = case [ByteString]
inner_spec of
        [] -> [Char]
-> (Int -> Reader (Vector ClickhouseType), Maybe (Int, ByteString))
forall a. HasCallStack => [Char] -> a
error [Char]
"No spec"
        [ByteString
scale'] ->
          if ByteString
"Decimal32" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
            then (Int -> Reader (Vector ClickhouseType)
readDecimal32, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
            else
              if ByteString
"Decimal64" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
                then (Int -> Reader (Vector ClickhouseType)
readDecimal64, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
                else (Int -> Reader (Vector ClickhouseType)
readDecimal128, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
        [ByteString
precision', ByteString
scale'] -> do
          let Just (Int
precision, ByteString
_) = ByteString -> Maybe (Int, ByteString)
readInt ByteString
precision'
          if Int
precision Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
9 Bool -> Bool -> Bool
|| ByteString
"Decimal32" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
            then (Int -> Reader (Vector ClickhouseType)
readDecimal32, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
            else
              if Int
precision Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
18 Bool -> Bool -> Bool
|| ByteString
"Decimal64" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
                then (Int -> Reader (Vector ClickhouseType)
readDecimal64, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
                else (Int -> Reader (Vector ClickhouseType)
readDecimal128, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
  Vector ClickhouseType
raw <- Int -> Reader (Vector ClickhouseType)
specific Int
n_rows
  let final :: Vector ClickhouseType
final = (ClickhouseType -> ClickhouseType)
-> Vector ClickhouseType -> Vector ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> ClickhouseType -> ClickhouseType
trans Int
scale) Vector ClickhouseType
raw
  Vector ClickhouseType -> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => a -> m a
return Vector ClickhouseType
final
  where
    readDecimal32 :: Int -> Reader (Vector ClickhouseType)
    readDecimal32 :: Int -> Reader (Vector ClickhouseType)
readDecimal32 Int
n_rows = Int -> ByteString -> Reader (Vector ClickhouseType)
readIntColumn Int
n_rows ByteString
"Int32"
    
    readDecimal64 :: Int -> Reader (Vector ClickhouseType)
    readDecimal64 :: Int -> Reader (Vector ClickhouseType)
readDecimal64 Int
n_rows = Int -> ByteString -> Reader (Vector ClickhouseType)
readIntColumn Int
n_rows ByteString
"Int64"

    readDecimal128 :: Int -> Reader (Vector ClickhouseType)
    readDecimal128 :: Int -> Reader (Vector ClickhouseType)
readDecimal128 Int
n_rows =
      Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (StateT Buffer IO ClickhouseType -> Reader (Vector ClickhouseType))
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall a b. (a -> b) -> a -> b
$ do
        Word64
lo <- StateT Buffer IO Word64
readBinaryUInt64
        Word64
hi <- StateT Buffer IO Word64
readBinaryUInt64
        ClickhouseType -> StateT Buffer IO ClickhouseType
forall (m :: * -> *) a. Monad m => a -> m a
return (ClickhouseType -> StateT Buffer IO ClickhouseType)
-> ClickhouseType -> StateT Buffer IO ClickhouseType
forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> ClickhouseType
CKUInt128 Word64
lo Word64
hi

    trans :: Int -> ClickhouseType -> ClickhouseType
    trans :: Int -> ClickhouseType -> ClickhouseType
trans Int
scale (CKInt32 Int32
x) = Float -> ClickhouseType
CKDecimal32 (Int32 -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
x Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Integer -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer
10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
scale))
    trans Int
scale (CKInt64 Int64
x) = Double -> ClickhouseType
CKDecimal64 (Int64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
x Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer
10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
scale))
    trans Int
scale (CKUInt128 Word64
lo Word64
hi) = Double -> ClickhouseType
CKDecimal128 (Word64 -> Word64 -> Int -> Double
word128_division Word64
hi Word64
lo Int
scale)

writeDecimal :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeDecimal :: ByteString -> ByteString -> Vector ClickhouseType -> Writer Builder
writeDecimal ByteString
col_name ByteString
spec Vector ClickhouseType
items = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
  let inner_specs :: [ByteString]
inner_specs = ByteString -> [ByteString]
getSpecs (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
9) (Int -> ByteString -> ByteString
BS.drop Int
8 ByteString
spec)
  let (Int -> Vector ClickhouseType -> Writer Builder
specific, Just (Int
pre_scale, ByteString
_)) = case [ByteString]
inner_specs of
        [] -> [Char]
-> (Int -> Vector ClickhouseType -> Writer Builder,
    Maybe (Int, ByteString))
forall a. HasCallStack => [Char] -> a
error [Char]
"No spec"
        [ByteString
scale'] ->
          if ByteString
"Decimal32" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
            then (Int -> Vector ClickhouseType -> Writer Builder
writeDecimal32, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
            else
              if ByteString
"Decimal64" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
                then (Int -> Vector ClickhouseType -> Writer Builder
writeDecimal64, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
                else (Int -> Vector ClickhouseType -> Writer Builder
writeDecimal128, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
        [ByteString
precision', ByteString
scale'] -> do
          let Just (Int
precision, ByteString
_) = ByteString -> Maybe (Int, ByteString)
readInt ByteString
precision'
          if Int
precision Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
9 Bool -> Bool -> Bool
|| ByteString
"Decimal32" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
            then (Int -> Vector ClickhouseType -> Writer Builder
writeDecimal32, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
            else
              if Int
precision Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
18 Bool -> Bool -> Bool
|| ByteString
"Decimal64" ByteString -> ByteString -> Bool
`isPrefixOf` ByteString
spec
                then (Int -> Vector ClickhouseType -> Writer Builder
writeDecimal64, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
                else (Int -> Vector ClickhouseType -> Writer Builder
writeDecimal128, ByteString -> Maybe (Int, ByteString)
readInt ByteString
scale')
  let scale :: Int
scale = Int
10 Int -> Int -> Int
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
pre_scale
  Int -> Vector ClickhouseType -> Writer Builder
specific Int
scale Vector ClickhouseType
items
  where
    writeDecimal32 :: Int -> Vector ClickhouseType -> Writer Builder
    writeDecimal32 :: Int -> Vector ClickhouseType -> Writer Builder
writeDecimal32 Int
scale Vector ClickhouseType
vec =
      (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
        ( \case
            CKDecimal32 Float
f32 -> Int32 -> Writer Builder
forall w. MonoidMap ByteString w => Int32 -> Writer w
writeBinaryInt32 (Int32 -> Writer Builder) -> Int32 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Integer -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Int32) -> Integer -> Int32
forall a b. (a -> b) -> a -> b
$ Float -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
floor (Float -> Integer) -> Float -> Integer
forall a b. (a -> b) -> a -> b
$ (Float
f32 Float -> Float -> Float
forall a. Num a => a -> a -> a
* Int -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
scale)
            ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error ([Char] -> Writer Builder) -> [Char] -> Writer Builder
forall a b. (a -> b) -> a -> b
$ ByteString -> [Char]
typeMismatchError ByteString
col_name
        )
        Vector ClickhouseType
vec
    writeDecimal64 :: Int -> Vector ClickhouseType -> Writer Builder
    writeDecimal64 :: Int -> Vector ClickhouseType -> Writer Builder
writeDecimal64 Int
scale Vector ClickhouseType
vec =
      (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
        ( \case
            CKDecimal64 Double
f64 -> Int32 -> Writer Builder
forall w. MonoidMap ByteString w => Int32 -> Writer w
writeBinaryInt32 (Int32 -> Writer Builder) -> Int32 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Integer -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Int32) -> Integer -> Int32
forall a b. (a -> b) -> a -> b
$ Double -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double -> Integer) -> Double -> Integer
forall a b. (a -> b) -> a -> b
$ (Double
f64 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
scale)
            ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error ([Char] -> Writer Builder) -> [Char] -> Writer Builder
forall a b. (a -> b) -> a -> b
$ ByteString -> [Char]
typeMismatchError ByteString
col_name
        )
        Vector ClickhouseType
vec
    writeDecimal128 :: Int -> Vector ClickhouseType -> Writer Builder
    writeDecimal128 :: Int -> Vector ClickhouseType -> Writer Builder
writeDecimal128 Int
scale Vector ClickhouseType
items = do
      (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
        ( \case
            CKDecimal128 Double
x -> do
              if Double
x Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
>= Double
0
                then do
                  Word64 -> Writer Builder
forall w. MonoidMap ByteString w => Word64 -> Writer w
writeBinaryUInt64 (Word64 -> Writer Builder) -> Word64 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Double -> Int -> Word64
low_bits_128 Double
x Int
scale
                  Word64 -> Writer Builder
forall w. MonoidMap ByteString w => Word64 -> Writer w
writeBinaryUInt64 (Word64 -> Writer Builder) -> Word64 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Double -> Int -> Word64
hi_bits_128 Double
x Int
scale
                else do
                  Word64 -> Writer Builder
forall w. MonoidMap ByteString w => Word64 -> Writer w
writeBinaryUInt64 (Word64 -> Writer Builder) -> Word64 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Double -> Int -> Word64
low_bits_negative_128 (- Double
x) Int
scale
                  Word64 -> Writer Builder
forall w. MonoidMap ByteString w => Word64 -> Writer w
writeBinaryUInt64 (Word64 -> Writer Builder) -> Word64 -> Writer Builder
forall a b. (a -> b) -> a -> b
$ Double -> Int -> Word64
hi_bits_negative_128 (- Double
x) Int
scale
        )
        Vector ClickhouseType
items

foreign import ccall unsafe "bigint.h word128_division" word128_division :: Word64 -> Word64 -> Int -> Double

foreign import ccall unsafe "bigint.h low_bits_128" low_bits_128 :: Double -> Int -> Word64

foreign import ccall unsafe "bigint.h hi_bits_128" hi_bits_128 :: Double -> Int -> Word64

foreign import ccall unsafe "bigint.h low_bits_negative_128" low_bits_negative_128 :: Double -> Int -> Word64

foreign import ccall unsafe "bigint.h hi_bits_negative_128" hi_bits_negative_128 :: Double -> Int -> Word64
----------------------------------------------------------------------------------------------
readIPv4 :: Int -> Reader (Vector ClickhouseType)
readIPv4 :: Int -> Reader (Vector ClickhouseType)
readIPv4 Int
n_rows = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows ((Word8, Word8, Word8, Word8) -> ClickhouseType
CKIPv4 ((Word8, Word8, Word8, Word8) -> ClickhouseType)
-> (Word32 -> (Word8, Word8, Word8, Word8))
-> Word32
-> ClickhouseType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IP4 -> (Word8, Word8, Word8, Word8)
ip4ToOctets (IP4 -> (Word8, Word8, Word8, Word8))
-> (Word32 -> IP4) -> Word32 -> (Word8, Word8, Word8, Word8)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> IP4
IP4 (Word32 -> ClickhouseType)
-> StateT Buffer IO Word32 -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO Word32
readBinaryUInt32)

readIPv6 :: Int -> Reader (Vector ClickhouseType)
readIPv6 :: Int -> Reader (Vector ClickhouseType)
readIPv6 Int
n_rows = Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows ((Word16, Word16, Word16, Word16, Word16, Word16, Word16, Word16)
-> ClickhouseType
CKIPv6 ((Word16, Word16, Word16, Word16, Word16, Word16, Word16, Word16)
 -> ClickhouseType)
-> (Word128
    -> (Word16, Word16, Word16, Word16, Word16, Word16, Word16,
        Word16))
-> Word128
-> ClickhouseType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IP6
-> (Word16, Word16, Word16, Word16, Word16, Word16, Word16, Word16)
ip6ToWords (IP6
 -> (Word16, Word16, Word16, Word16, Word16, Word16, Word16,
     Word16))
-> (Word128 -> IP6)
-> Word128
-> (Word16, Word16, Word16, Word16, Word16, Word16, Word16, Word16)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word128 -> IP6
IP6 (Word128 -> ClickhouseType)
-> StateT Buffer IO Word128 -> StateT Buffer IO ClickhouseType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT Buffer IO Word128
readBinaryUInt128)

writeIPv4 :: ByteString -> Vector ClickhouseType -> Writer Builder
writeIPv4 :: ByteString -> Vector ClickhouseType -> Writer Builder
writeIPv4 ByteString
col_name =
  (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
    ( \case
        CKIPv4 (Word8
w1, Word8
w2, Word8
w3, Word8
w4) ->
          Word32 -> Writer Builder
forall w. MonoidMap ByteString w => Word32 -> Writer w
writeBinaryUInt32 (Word32 -> Writer Builder) -> Word32 -> Writer Builder
forall a b. (a -> b) -> a -> b
$
            IP4 -> Word32
unIP4 (IP4 -> Word32) -> IP4 -> Word32
forall a b. (a -> b) -> a -> b
$
              Word8 -> Word8 -> Word8 -> Word8 -> IP4
ip4FromOctets Word8
w1 Word8
w2 Word8
w3 Word8
w4
        ClickhouseType
CKNull -> Int32 -> Writer Builder
forall w. MonoidMap ByteString w => Int32 -> Writer w
writeBinaryInt32 Int32
0
        ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error ([Char] -> Writer Builder) -> [Char] -> Writer Builder
forall a b. (a -> b) -> a -> b
$ ByteString -> [Char]
typeMismatchError ByteString
col_name
    )

writeIPv6 :: ByteString -> Vector ClickhouseType -> Writer Builder
writeIPv6 :: ByteString -> Vector ClickhouseType -> Writer Builder
writeIPv6 ByteString
col_name =
  (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
    ( \case
        CKIPv6 (Word16
w1, Word16
w2, Word16
w3, Word16
w4, Word16
w5, Word16
w6, Word16
w7, Word16
w8) ->
          Word128 -> Writer Builder
forall w. MonoidMap ByteString w => Word128 -> Writer w
writeBinaryUInt128 (Word128 -> Writer Builder) -> Word128 -> Writer Builder
forall a b. (a -> b) -> a -> b
$
            IP6 -> Word128
unIP6 (IP6 -> Word128) -> IP6 -> Word128
forall a b. (a -> b) -> a -> b
$
              Word16
-> Word16
-> Word16
-> Word16
-> Word16
-> Word16
-> Word16
-> Word16
-> IP6
ip6FromWords Word16
w1 Word16
w2 Word16
w3 Word16
w4 Word16
w5 Word16
w6 Word16
w7 Word16
w8
        ClickhouseType
CKNull -> Word64 -> Writer Builder
forall w. MonoidMap ByteString w => Word64 -> Writer w
writeBinaryUInt64 Word64
0
        ClickhouseType
_ -> [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error ([Char] -> Writer Builder) -> [Char] -> Writer Builder
forall a b. (a -> b) -> a -> b
$ ByteString -> [Char]
typeMismatchError ByteString
col_name
    )

----------------------------------------------------------------------------------------------
readSimpleAggregateFunction :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readSimpleAggregateFunction :: ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readSimpleAggregateFunction ServerInfo
server_info Int
n_rows ByteString
spec = do
  let l :: Int
l = ByteString -> Int
BS.length ByteString
spec
  let [ByteString
func, ByteString
cktype] = ByteString -> [ByteString]
getSpecs (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
BS.take (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
25) (Int -> ByteString -> ByteString
BS.drop Int
24 ByteString
spec)
  ServerInfo -> Int -> ByteString -> Reader (Vector ClickhouseType)
readColumn ServerInfo
server_info Int
n_rows ByteString
cktype
----------------------------------------------------------------------------------------------
readUUID :: Int -> Reader (Vector ClickhouseType)
readUUID :: Int -> Reader (Vector ClickhouseType)
readUUID Int
n_rows = do
  Int
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM Int
n_rows (StateT Buffer IO ClickhouseType -> Reader (Vector ClickhouseType))
-> StateT Buffer IO ClickhouseType
-> Reader (Vector ClickhouseType)
forall a b. (a -> b) -> a -> b
$ do
    Word32
w2 <- StateT Buffer IO Word32
readBinaryUInt32
    Word32
w1 <- StateT Buffer IO Word32
readBinaryUInt32
    Word32
w3 <- StateT Buffer IO Word32
readBinaryUInt32
    Word32
w4 <- StateT Buffer IO Word32
readBinaryUInt32
    ClickhouseType -> StateT Buffer IO ClickhouseType
forall (m :: * -> *) a. Monad m => a -> m a
return (ClickhouseType -> StateT Buffer IO ClickhouseType)
-> ClickhouseType -> StateT Buffer IO ClickhouseType
forall a b. (a -> b) -> a -> b
$
      ByteString -> ClickhouseType
CKString (ByteString -> ClickhouseType) -> ByteString -> ClickhouseType
forall a b. (a -> b) -> a -> b
$
        [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$
          UUID -> [Char]
UUID.toString (UUID -> [Char]) -> UUID -> [Char]
forall a b. (a -> b) -> a -> b
$ Word32 -> Word32 -> Word32 -> Word32 -> UUID
UUID.fromWords Word32
w1 Word32
w2 Word32
w3 Word32
w4

writeUUID :: ByteString -> Vector ClickhouseType -> Writer Builder
writeUUID :: ByteString -> Vector ClickhouseType -> Writer Builder
writeUUID ByteString
col_name =
  (ClickhouseType -> Writer Builder)
-> Vector ClickhouseType -> Writer Builder
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_
    ( \case
        CKString ByteString
uuid_str -> do
          case [Char] -> Maybe UUID
UUID.fromString ([Char] -> Maybe UUID) -> [Char] -> Maybe UUID
forall a b. (a -> b) -> a -> b
$ ByteString -> [Char]
C8.unpack ByteString
uuid_str of
            Maybe UUID
Nothing ->
              [Char] -> Writer Builder
forall a. HasCallStack => [Char] -> a
error ([Char] -> Writer Builder) -> [Char] -> Writer Builder
forall a b. (a -> b) -> a -> b
$
                [Char]
"UUID parsing error in the column"
                  [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ByteString -> [Char]
forall a. Show a => a -> [Char]
show ByteString
col_name
                  [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" wrong data: "
                  [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ByteString -> [Char]
forall a. Show a => a -> [Char]
show ByteString
uuid_str
            Just UUID
uuid -> do
              let (Word32
w2, Word32
w1, Word32
w3, Word32
w4) = UUID -> (Word32, Word32, Word32, Word32)
UUID.toWords UUID
uuid
              Word32 -> Writer Builder
forall w. MonoidMap ByteString w => Word32 -> Writer w
writeBinaryUInt32 Word32
w1
              Word32 -> Writer Builder
forall w. MonoidMap ByteString w => Word32 -> Writer w
writeBinaryUInt32 Word32
w2
              Word32 -> Writer Builder
forall w. MonoidMap ByteString w => Word32 -> Writer w
writeBinaryUInt32 Word32
w3
              Word32 -> Writer Builder
forall w. MonoidMap ByteString w => Word32 -> Writer w
writeBinaryUInt32 Word32
w4
        ClickhouseType
CKNull -> do
          Word64 -> Writer Builder
forall w. MonoidMap ByteString w => Word64 -> Writer w
writeBinaryUInt64 Word64
0
          Word64 -> Writer Builder
forall w. MonoidMap ByteString w => Word64 -> Writer w
writeBinaryUInt64 Word64
0
    )

----------------------------------------------------------------------------------------------
---Helpers
#define COMMA 44
#define SPACE 32

-- | Get rid of commas and spaces
getSpecs :: ByteString -> [ByteString]
getSpecs :: ByteString -> [ByteString]
getSpecs ByteString
str = (Word8 -> Bool) -> ByteString -> [ByteString]
BS.splitWith (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== COMMA) (BS.filter (/= SPACE) str)

transpose :: Vector (Vector ClickhouseType) -> Vector (Vector ClickhouseType)
transpose :: Vector (Vector ClickhouseType) -> Vector (Vector ClickhouseType)
transpose = Vector (Vector ClickhouseType) -> Vector (Vector ClickhouseType)
forall a. Vector (Vector a) -> Vector (Vector a)
rotate 
  where
    rotate :: Vector (Vector a) -> Vector (Vector a)
rotate Vector (Vector a)
matrix =
      let transposedList :: [[a]]
transposedList = [[a]] -> [[a]]
forall a. [[a]] -> [[a]]
List.transpose (Vector a -> [a]
forall a. Vector a -> [a]
V.toList (Vector a -> [a]) -> [Vector a] -> [[a]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Vector (Vector a) -> [Vector a]
forall a. Vector a -> [a]
V.toList Vector (Vector a)
matrix)
          toVector :: Vector (Vector a)
toVector = [a] -> Vector a
forall a. [a] -> Vector a
V.fromList ([a] -> Vector a) -> Vector [a] -> Vector (Vector a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [[a]] -> Vector [a]
forall a. [a] -> Vector a
V.fromList [[a]]
transposedList
       in Vector (Vector a)
toVector

typeMismatchError :: ByteString -> String
typeMismatchError :: ByteString -> [Char]
typeMismatchError ByteString
col_name = [Char]
"Type mismatch in the column " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ByteString -> [Char]
forall a. Show a => a -> [Char]
show ByteString
col_name

-- | print in format
putStrLn :: Vector (Vector ClickhouseType) -> IO ()
putStrLn :: Vector (Vector ClickhouseType) -> IO ()
putStrLn Vector (Vector ClickhouseType)
v = ByteString -> IO ()
C8.putStrLn (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ ByteString -> [ByteString] -> ByteString
BS.intercalate ByteString
"\n" ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ Vector ByteString -> [ByteString]
forall a. Vector a -> [a]
V.toList (Vector ByteString -> [ByteString])
-> Vector ByteString -> [ByteString]
forall a b. (a -> b) -> a -> b
$ (Vector ClickhouseType -> ByteString)
-> Vector (Vector ClickhouseType) -> Vector ByteString
forall a b. (a -> b) -> Vector a -> Vector b
V.map Vector ClickhouseType -> ByteString
to_str Vector (Vector ClickhouseType)
v
  where
    to_str :: Vector ClickhouseType -> ByteString
    to_str :: Vector ClickhouseType -> ByteString
to_str Vector ClickhouseType
row = ByteString -> [ByteString] -> ByteString
BS.intercalate ByteString
"," ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ Vector ByteString -> [ByteString]
forall a. Vector a -> [a]
V.toList (Vector ByteString -> [ByteString])
-> Vector ByteString -> [ByteString]
forall a b. (a -> b) -> a -> b
$ (ClickhouseType -> ByteString)
-> Vector ClickhouseType -> Vector ByteString
forall a b. (a -> b) -> Vector a -> Vector b
V.map ClickhouseType -> ByteString
help Vector ClickhouseType
row

    help :: ClickhouseType -> ByteString
    help :: ClickhouseType -> ByteString
help (CKString ByteString
s) = ByteString
s
    help (CKDecimal64 Double
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Double -> [Char]
forall a. Show a => a -> [Char]
show Double
n
    help (CKDecimal32 Float
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Float -> [Char]
forall a. Show a => a -> [Char]
show Float
n
    help (CKDecimal Float
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Float -> [Char]
forall a. Show a => a -> [Char]
show Float
n
    help (CKInt8 Int8
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int8 -> [Char]
forall a. Show a => a -> [Char]
show Int8
n
    help (CKInt16 Int16
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int16 -> [Char]
forall a. Show a => a -> [Char]
show Int16
n
    help (CKInt32 Int32
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int32 -> [Char]
forall a. Show a => a -> [Char]
show Int32
n
    help (CKInt64 Int64
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int64 -> [Char]
forall a. Show a => a -> [Char]
show Int64
n
    help (CKUInt8 Word8
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Word8 -> [Char]
forall a. Show a => a -> [Char]
show Word8
n
    help (CKUInt16 Word16
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Word16 -> [Char]
forall a. Show a => a -> [Char]
show Word16
n
    help (CKUInt32 Word32
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Word32 -> [Char]
forall a. Show a => a -> [Char]
show Word32
n
    help (CKUInt64 Word64
n) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ Word64 -> [Char]
forall a. Show a => a -> [Char]
show Word64
n
    help (CKTuple Vector ClickhouseType
xs) = ByteString
"(" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Vector ClickhouseType -> ByteString
to_str Vector ClickhouseType
xs ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
")"
    help (CKArray Vector ClickhouseType
xs) = ByteString
"[" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Vector ClickhouseType -> ByteString
to_str Vector ClickhouseType
xs ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"]"
    help  ClickhouseType
CKNull = ByteString
"null"
    help (CKIPv4 (Word8, Word8, Word8, Word8)
ip4) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ (Word8, Word8, Word8, Word8) -> [Char]
forall a. Show a => a -> [Char]
show (Word8, Word8, Word8, Word8)
ip4
    help (CKIPv6 (Word16, Word16, Word16, Word16, Word16, Word16, Word16, Word16)
ip6) = [Char] -> ByteString
C8.pack ([Char] -> ByteString) -> [Char] -> ByteString
forall a b. (a -> b) -> a -> b
$ (Word16, Word16, Word16, Word16, Word16, Word16, Word16, Word16)
-> [Char]
forall a. Show a => a -> [Char]
show (Word16, Word16, Word16, Word16, Word16, Word16, Word16, Word16)
ip6
    help (CKDate Integer
y Int
m Int
d) =
      [Char] -> ByteString
C8.pack (Integer -> [Char]
forall a. Show a => a -> [Char]
show Integer
y)
        ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"-"
        ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> [Char] -> ByteString
C8.pack (Int -> [Char]
forall a. Show a => a -> [Char]
show Int
m)
        ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"-"
        ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> [Char] -> ByteString
C8.pack (Int -> [Char]
forall a. Show a => a -> [Char]
show Int
d)