Skip to content

Commit

Permalink
Mysql (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
keynmol authored Nov 19, 2023
1 parent 5bff0e2 commit 225d57d
Show file tree
Hide file tree
Showing 9 changed files with 3,650 additions and 28 deletions.
30 changes: 15 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,25 @@ on:
branches: ["*"]

env:
JAVA_OPTS: "-Xmx4G -Dsbt.task.timings=true -Dsbt.task.timings.on.shutdown=true"
JAVA_OPTS: "-Xmx4G"

jobs:
build:
name: CI on ${{matrix.os}} ${{matrix.segment}} out of 3
strategy:
fail-fast: false
matrix:
os: [macos-11, ubuntu-20.04]
os: [macos-12, ubuntu-22.04]
segment: [1, 2, 3]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2

- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
cache: sbt

- name: Cache vcpkg
uses: actions/cache@v3
Expand All @@ -38,42 +39,41 @@ jobs:

- uses: rui314/setup-mold@v1

- uses: actions/setup-python@v4
with:
python-version: '3.11'

- name: Setup for Scala Native
run: |
PLATFORM="$(uname)"
if [ $PLATFORM == "Darwin" ]; then
echo "It's a Mac"
brew install llvm@14 ninja
echo "LLVM_BIN=/usr/local/opt/llvm@14/bin" >> $GITHUB_ENV
else
echo "It's a Linux"
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 14
sudo apt-get install ninja-build
echo "LLVM_BIN=/usr/lib/llvm-14/bin" >> $GITHUB_ENV
fi
- name: Setup for examples
run: |
./manual_setup.sh
PLATFORM="$(uname)"
if [ $PLATFORM == "Darwin" ]; then
echo "It's a Mac"
python3 -m pip install packaging
else
docker run -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -d postgres
docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql-password -e MYSQL_DATABASE=mysql_db -p 3306:3306 -d mysql
docker run -p 6379:6379 -d redis
fi
./manual_setup.sh
- name: Run examples
run: |
PLATFORM="$(uname)"
if [ $PLATFORM == "Darwin" ]; then
echo "It's a Mac"
LLVM_BIN=/usr/local/opt/llvm@14/bin sbt 'runBatchedExamples ${{matrix.segment}} 3'
else
echo "It's a Linux"
LLVM_BIN=/usr/lib/llvm-14/bin sbt 'runBatchedExamples ${{matrix.segment}} 3'
fi
run: sbt 'runBatchedExamples ${{matrix.segment}} 3'

mergify-build-checkpoint:
runs-on: ubuntu-latest
Expand Down
61 changes: 54 additions & 7 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import bindgen.plugin.BindgenMode
import com.indoorvivants.detective.Platform.OS.*
import com.indoorvivants.detective.Platform
import bindgen.interface.Binding
Expand All @@ -9,7 +10,7 @@ Global / onChangedBuildSource := ReloadOnSourceChanges
ThisBuild / resolvers += Resolver.sonatypeRepo("snapshots")

lazy val Versions = new {
val Scala = "3.2.2"
val Scala = "3.3.1"
}

lazy val root = project
Expand All @@ -26,6 +27,7 @@ lazy val root = project
lua,
openssl,
postgres,
mysql,
redis,
rocksdb,
sqlite,
Expand All @@ -47,8 +49,7 @@ lazy val `tree-sitter` = project
Binding(
baseDirectory.value / "tree-sitter" / "lib" / "include" / "tree_sitter" / "api.h",
"treesitter",
cImports = List("tree_sitter/api.h"),
clangFlags = List("-std=gnu99")
cImports = List("tree_sitter/api.h")
)
},
// Copy generated Scala parser
Expand All @@ -57,7 +58,7 @@ lazy val `tree-sitter` = project
baseDirectory.value / "tree-sitter-scala" / "src"
val resourcesFolder = (Compile / resourceManaged).value / "scala-native"

val fileNames = List("parser.c", "scanner.c")
val fileNames = List("parser.c", "scanner.c", "stack.h")

fileNames.foreach { fileName =>
IO.copyFile(scalaParserLocation / fileName, resourcesFolder / fileName)
Expand All @@ -77,7 +78,7 @@ lazy val `tree-sitter` = project
)
)
.withCompileOptions(
conf.compileOptions ++ List(s"-I${base / "lib" / "include"}")
List(s"-I${base / "lib" / "include"}") ++ conf.compileOptions
)
}
)
Expand Down Expand Up @@ -157,6 +158,52 @@ lazy val postgres =
)
.settings(configurePlatform())

lazy val mysql =
project
.in(file("example-mysql"))
.enablePlugins(ScalaNativePlugin, BindgenPlugin, VcpkgNativePlugin)
.settings(
scalaVersion := Versions.Scala,
vcpkgDependencies := VcpkgDependencies("libmysql", "openssl", "zlib"),
// Mysql package in vcpkg is absolutely messed up
vcpkgNativeConfig ~= { _.addRenamedLibrary("libmysql", "mysqlclient") },
nativeConfig := {

val config = nativeConfig.value
config.withLinkingOptions(config.linkingOptions.flatMap {
case "-lresolv-lresolv" => Some("-lresolv")
case "-lm-lresolv" => None
case other => Some(other)
})

},
bindgenBindings += {
val actualIncludeFolder = new File(
vcpkgConfigurator.value.pkgConfig
.compilationFlags("mysqlclient")
.toList
.filter(_.contains("include/mysql"))
.head
.stripPrefix("-I")
)

Binding(
actualIncludeFolder / "mysql.h",
"libmysql",
linkName = Some("mysqlclient"),
cImports = List("mysql/mysql.h"),
clangFlags = vcpkgConfigurator.value.pkgConfig
.updateCompilationFlags(List("-std=gnu99"), "mysqlclient")
.toList
)
},
bindgenMode := BindgenMode.Manual(
scalaDir = sourceDirectory.value / "main" / "scala" / "generated",
cDir = (Compile / resourceDirectory).value / "scala-native"
)
)
.settings(configurePlatform())

lazy val sqlite =
project
.in(file("example-sqlite"))
Expand Down Expand Up @@ -403,8 +450,8 @@ def projectCommands(st: State) = {
val exceptions: Set[String] =
if (sys.env.contains("CI")) {
val platformSpecific = Platform.os match {
// postgres, redis - these require docker containers so we don't run them on CI
case MacOS => Set("postgres", "redis")
// these require docker containers so we don't run them on CI
case MacOS => Set("mysql", "postgres", "redis")
case _ => Set.empty
}

Expand Down
Empty file.
71 changes: 71 additions & 0 deletions example-mysql/src/main/scala/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import libmysql.all.*
import scalanative.unsafe.*
import scalanative.unsigned.*

def mysql_assert[A](f: => A, conn: Ptr[MYSQL], msg: String) =
val result = f
assert(
result != null, {
val err =
s"$msg: ${fromCString(mysql_error(conn))}"
mysql_close(conn)
err
}
)
result
end mysql_assert

@main def hello =
val conn = mysql_init(null)

assert(conn != null, "mysql_init failed")

val newValue = stackalloc[mysql_protocol_type]()
!newValue = mysql_protocol_type.MYSQL_PROTOCOL_TCP

mysql_options(
conn,
mysql_option.MYSQL_OPT_PROTOCOL,
newValue.asInstanceOf
)

val real_connect =
mysql_assert(
mysql_real_connect(
mysql = conn,
host = c"localhost",
user = c"mysql",
passwd = c"mysql-password",
db = c"mysql_db",
port = 3306.toUInt,
unix_socket = null,
clientflag = 0.toUInt
),
conn,
"mysql_real_connect failed"
)

mysql_assert(
mysql_query(conn, c"select 1, 'hello', 'world!'"),
conn,
"mysql_query failed"
)

val res =
mysql_assert(mysql_use_result(conn), conn, "mysql_use_result failed")

var lastRow: MYSQL_ROW = null.asInstanceOf

inline def fetchRow() =
lastRow = mysql_fetch_row(res)
lastRow

while fetchRow() != null.asInstanceOf do
val columns = mysql_num_fields(res)
println("-----")
for i <- 0 until columns.toInt do
print(s"${fromCString(lastRow.value(i))} |")

mysql_free_result(res)
mysql_close(conn)
end hello
Loading

0 comments on commit 225d57d

Please sign in to comment.