diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9b4fa81..30d7c116 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,10 +27,10 @@ jobs: name: Build and Test strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-22.04] scala: [2.12.17, 2.13.10, 3.2.1] java: [temurin@11] - project: [rootJS, rootJVM] + project: [rootJS, rootJVM, rootNative] runs-on: ${{ matrix.os }} steps: - name: Checkout current branch (full) @@ -66,6 +66,10 @@ jobs: ~/Library/Caches/Coursier/v1 key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} + - name: Install brew formulae (ubuntu) + if: (matrix.project == 'rootNative') && startsWith(matrix.os, 'ubuntu') + run: /home/linuxbrew/.linuxbrew/bin/brew install s2n utf8proc + - name: Set up cert permissions run: | chmod 600 world/server.key @@ -78,38 +82,42 @@ jobs: run: sbt githubWorkflowCheck - name: Check Headers - run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' headerCheckAll + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' headerCheckAll - name: Check headers and formatting if: matrix.java == 'temurin@11' - run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck - name: scalaJSLink if: matrix.project == 'rootJS' - run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' Test/scalaJSLinkerResult + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' Test/scalaJSLinkerResult + + - name: nativeLink + if: matrix.project == 'rootNative' + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' Test/nativeLink - name: Test - run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' test + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' test - name: Check binary compatibility if: matrix.java == 'temurin@11' - run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' mimaReportBinaryIssues + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' mimaReportBinaryIssues - name: Generate API documentation if: matrix.java == 'temurin@11' - run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' doc + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' doc - name: Check Doc Site (2.13.10 JVM only) if: matrix.scala == '2.13.10' && matrix.project == 'rootJVM' - run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' docs/makeSite + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' docs/makeSite - name: Make target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') - run: mkdir -p modules/circe/.jvm/target target .js/target modules/docs/target modules/core/js/target modules/circe/.js/target modules/core/jvm/target modules/tests/js/target .jvm/target .native/target modules/refined/.js/target modules/refined/.jvm/target modules/tests/jvm/target modules/example/target project/target + run: mkdir -p modules/circe/.jvm/target target .js/target modules/core/native/target modules/docs/target modules/core/js/target modules/circe/.js/target modules/core/jvm/target modules/tests/js/target modules/refined/.native/target .jvm/target .native/target modules/refined/.js/target modules/refined/.jvm/target modules/circe/.native/target modules/tests/jvm/target modules/example/target modules/tests/native/target project/target - name: Compress target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') - run: tar cf targets.tar modules/circe/.jvm/target target .js/target modules/docs/target modules/core/js/target modules/circe/.js/target modules/core/jvm/target modules/tests/js/target .jvm/target .native/target modules/refined/.js/target modules/refined/.jvm/target modules/tests/jvm/target modules/example/target project/target + run: tar cf targets.tar modules/circe/.jvm/target target .js/target modules/core/native/target modules/docs/target modules/core/js/target modules/circe/.js/target modules/core/jvm/target modules/tests/js/target modules/refined/.native/target .jvm/target .native/target modules/refined/.js/target modules/refined/.jvm/target modules/circe/.native/target modules/tests/jvm/target modules/example/target modules/tests/native/target project/target - name: Upload target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') @@ -124,7 +132,7 @@ jobs: if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-22.04] scala: [2.13.10] java: [temurin@11] runs-on: ${{ matrix.os }} @@ -182,6 +190,16 @@ jobs: tar xf targets.tar rm targets.tar + - name: Download target directories (2.12.17, rootNative) + uses: actions/download-artifact@v2 + with: + name: target-${{ matrix.os }}-${{ matrix.java }}-2.12.17-rootNative + + - name: Inflate target directories (2.12.17, rootNative) + run: | + tar xf targets.tar + rm targets.tar + - name: Download target directories (2.13.10, rootJS) uses: actions/download-artifact@v2 with: @@ -202,6 +220,16 @@ jobs: tar xf targets.tar rm targets.tar + - name: Download target directories (2.13.10, rootNative) + uses: actions/download-artifact@v2 + with: + name: target-${{ matrix.os }}-${{ matrix.java }}-2.13.10-rootNative + + - name: Inflate target directories (2.13.10, rootNative) + run: | + tar xf targets.tar + rm targets.tar + - name: Download target directories (3.2.1, rootJS) uses: actions/download-artifact@v2 with: @@ -222,6 +250,16 @@ jobs: tar xf targets.tar rm targets.tar + - name: Download target directories (3.2.1, rootNative) + uses: actions/download-artifact@v2 + with: + name: target-${{ matrix.os }}-${{ matrix.java }}-3.2.1-rootNative + + - name: Inflate target directories (3.2.1, rootNative) + run: | + tar xf targets.tar + rm targets.tar + - name: Import signing key if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE == '' run: echo $PGP_SECRET | base64 -di | gpg --import @@ -234,7 +272,7 @@ jobs: (echo "$PGP_PASSPHRASE"; echo; echo) | gpg --command-fd 0 --pinentry-mode loopback --change-passphrase $(gpg --list-secret-keys --with-colons 2> /dev/null | grep '^sec:' | cut --delimiter ':' --fields 5 | tail -n 1) - name: Publish - run: sbt '++ ${{ matrix.scala }}' tlRelease + run: sbt '++${{ matrix.scala }}' tlRelease coverage: name: Generate coverage report (2.13.10 JVM only) @@ -286,7 +324,7 @@ jobs: - name: Start up Postgres run: docker-compose up -d - - run: sbt '++ ${{ matrix.scala }}' coverage rootJVM/test coverageReport + - run: sbt '++${{ matrix.scala }}' coverage rootJVM/test coverageReport - name: Upload code coverage data run: 'bash <(curl -s https://codecov.io/bash)' diff --git a/build.sbt b/build.sbt index 166e8430..8f4fe0e5 100644 --- a/build.sbt +++ b/build.sbt @@ -17,9 +17,13 @@ ThisBuild / developers := List( ThisBuild / tlCiReleaseBranches := Seq("main") // publish snapshits on `main` ThisBuild / tlSonatypeUseLegacyHost := false +ThisBuild / githubWorkflowOSes := Seq("ubuntu-22.04") ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.temurin("11")) ThisBuild / tlJdkRelease := Some(8) +ThisBuild / githubWorkflowBuildPreamble ++= nativeBrewInstallWorkflowSteps.value +ThisBuild / nativeBrewInstallCond := Some("matrix.project == 'rootNative'") + lazy val setupCertAndDocker = Seq( WorkflowStep.Run( commands = List("chmod 600 world/server.key", "sudo chown 999 world/server.key"), @@ -69,8 +73,8 @@ ThisBuild / libraryDependencySchemes ++= Seq( ) // This is used in a couple places -lazy val fs2Version = "3.3.0" -lazy val natchezVersion = "0.1.6" +lazy val fs2Version = "3.4.0" +lazy val natchezVersion = "0.2.2" // Global Settings lazy val commonSettings = Seq( @@ -97,9 +101,6 @@ lazy val commonSettings = Seq( "-sourcepath", (LocalRootProject / baseDirectory).value.getAbsolutePath, "-doc-source-url", "https://github.com/tpolecat/skunk/blob/v" + version.value + "€{FILE_PATH}.scala", ), - libraryDependencies ++= Seq( - compilerPlugin("org.typelevel" %% "kind-projector" % "0.13.2" cross CrossVersion.full), - ).filterNot(_ => tlIsScala3.value), // Coverage Exclusions coverageExcludedPackages := "ffstest.*;tests.*;example.*;natchez.http4s.*", @@ -107,27 +108,6 @@ lazy val commonSettings = Seq( // uncomment in case of emergency // scalacOptions ++= { if (scalaVersion.value.startsWith("3.")) Seq("-source:3.0-migration") else Nil }, - // Add some more source directories - Compile / unmanagedSourceDirectories ++= { - val sourceDir = (Compile / sourceDirectory).value - CrossVersion.partialVersion(scalaVersion.value) match { - case Some((3, _)) => Seq(sourceDir / "scala-2.13+", file(sourceDir.getPath.replaceFirst("jvm", "shared").replaceFirst("js", "shared")) / "scala-2.13+") - case Some((2, 12)) => Seq() - case Some((2, _)) => Seq(sourceDir / "scala-2.13+", file(sourceDir.getPath.replaceFirst("jvm", "shared").replaceFirst("js", "shared")) / "scala-2.13+") - case _ => Seq() - } - }, - - - // dottydoc really doesn't work at all right now - Compile / doc / sources := { - val old = (Compile / doc / sources).value - if (scalaVersion.value.startsWith("3.")) - Seq() - else - old - }, - ) lazy val skunk = tlCrossRootProject @@ -135,7 +115,7 @@ lazy val skunk = tlCrossRootProject .aggregate(core, tests, circe, refined, example) .settings(commonSettings) -lazy val core = crossProject(JVMPlatform, JSPlatform) +lazy val core = crossProject(JVMPlatform, JSPlatform, NativePlatform) .crossType(CrossType.Full) .in(file("modules/core")) .enablePlugins(AutomateHeaderPlugin) @@ -153,14 +133,18 @@ lazy val core = crossProject(JVMPlatform, JSPlatform) "org.scodec" %%% "scodec-core" % (if (tlIsScala3.value) "2.2.0" else "1.11.10"), "org.scodec" %%% "scodec-cats" % "1.2.0", "org.tpolecat" %%% "natchez-core" % natchezVersion, - "org.tpolecat" %%% "sourcepos" % "1.0.1", + "org.tpolecat" %%% "sourcepos" % "1.1.0", "org.scala-lang.modules" %%% "scala-collection-compat" % "2.8.1", - ) ++ Seq( - "com.beachape" %%% "enumeratum" % "1.6.1", - ).filterNot(_ => tlIsScala3.value) + ) ).jvmSettings( libraryDependencies += "com.ongres.scram" % "client" % "2.1", - ).jsSettings( + ) + .platformsSettings(JVMPlatform, JSPlatform)( + libraryDependencies ++= Seq( + "com.beachape" %%% "enumeratum" % "1.6.1", + ).filterNot(_ => tlIsScala3.value) + ) + .platformsSettings(JSPlatform, NativePlatform)( libraryDependencies ++= Seq( "com.armanbilge" %%% "saslprep" % "0.1.1", "io.github.cquiroz" %%% "scala-java-time" % "2.4.0", @@ -168,7 +152,7 @@ lazy val core = crossProject(JVMPlatform, JSPlatform) ), ) -lazy val refined = crossProject(JVMPlatform, JSPlatform) +lazy val refined = crossProject(JVMPlatform, JSPlatform, NativePlatform) .crossType(CrossType.Pure) .in(file("modules/refined")) .dependsOn(core) @@ -180,7 +164,7 @@ lazy val refined = crossProject(JVMPlatform, JSPlatform) ) ) -lazy val circe = crossProject(JVMPlatform, JSPlatform) +lazy val circe = crossProject(JVMPlatform, JSPlatform, NativePlatform) .crossType(CrossType.Pure) .in(file("modules/circe")) .dependsOn(core) @@ -194,7 +178,7 @@ lazy val circe = crossProject(JVMPlatform, JSPlatform) ) ) -lazy val tests = crossProject(JVMPlatform, JSPlatform) +lazy val tests = crossProject(JVMPlatform, JSPlatform, NativePlatform) .crossType(CrossType.Full) .in(file("modules/tests")) .dependsOn(core, circe) @@ -203,21 +187,26 @@ lazy val tests = crossProject(JVMPlatform, JSPlatform) .settings( scalacOptions -= "-Xfatal-warnings", libraryDependencies ++= Seq( - "org.scalameta" %%% "munit" % "0.7.29", - "org.scalameta" % "junit-interface" % "0.7.29", - "org.typelevel" %%% "scalacheck-effect-munit" % "1.0.4", - "org.typelevel" %%% "munit-cats-effect-3" % "1.0.7", + "org.scalameta" %%% "munit" % "1.0.0-M6", + "org.scalameta" % "junit-interface" % "1.0.0-M6", + "org.typelevel" %%% "scalacheck-effect-munit" % "2.0.0-M2", + "org.typelevel" %%% "munit-cats-effect" % "2.0.0-M3", "org.typelevel" %%% "cats-free" % "2.9.0", "org.typelevel" %%% "cats-laws" % "2.9.0", - "org.typelevel" %%% "discipline-munit" % "1.0.9", - ) ++ Seq( - "io.chrisdavenport" %%% "cats-time" % "0.3.4", - ).filterNot(_ => scalaVersion.value.startsWith("3.")), + "org.typelevel" %%% "discipline-munit" % "2.0.0-M3", + "org.typelevel" %%% "cats-time" % "0.5.1", + ), testFrameworks += new TestFramework("munit.Framework") ) .jsSettings( Test / scalaJSLinkerConfig ~= (_.withModuleKind(ModuleKind.CommonJSModule)), ) + .nativeEnablePlugins(ScalaNativeBrewedConfigPlugin) + .nativeSettings( + libraryDependencies += "com.armanbilge" %%% "epollcat" % "0.0-ab1026e", + Test / nativeBrewFormulas ++= Set("s2n", "utf8proc"), + Test / envVars ++= Map("S2N_DONT_MLOCK" -> "1") + ) lazy val example = project .in(file("modules/example")) diff --git a/modules/core/shared/src/main/scala-2/SqlState.scala b/modules/core/js-jvm/src/main/scala-2/SqlState.scala similarity index 100% rename from modules/core/shared/src/main/scala-2/SqlState.scala rename to modules/core/js-jvm/src/main/scala-2/SqlState.scala diff --git a/modules/core/shared/src/main/scala-2/codec/EnumCodecPlatform.scala b/modules/core/js-jvm/src/main/scala-2/codec/EnumCodecPlatform.scala similarity index 100% rename from modules/core/shared/src/main/scala-2/codec/EnumCodecPlatform.scala rename to modules/core/js-jvm/src/main/scala-2/codec/EnumCodecPlatform.scala diff --git a/modules/core/js/src/main/scala/SSLPlatform.scala b/modules/core/js-native/src/main/scala/SSLPlatform.scala similarity index 100% rename from modules/core/js/src/main/scala/SSLPlatform.scala rename to modules/core/js-native/src/main/scala/SSLPlatform.scala diff --git a/modules/core/js/src/main/scala/net/message/Scram.scala b/modules/core/js-native/src/main/scala/message/Scram.scala similarity index 76% rename from modules/core/js/src/main/scala/net/message/Scram.scala rename to modules/core/js-native/src/main/scala/message/Scram.scala index e01678d2..68ac6c03 100644 --- a/modules/core/js/src/main/scala/net/message/Scram.scala +++ b/modules/core/js-native/src/main/scala/message/Scram.scala @@ -8,16 +8,13 @@ import com.armanbilge.SaslPrep import scodec.bits.ByteVector import scodec.codecs.utf8 -import scala.scalajs.js -import scala.scalajs.js.typedarray.Uint8Array - /** * Partial implementation of [RFC5802](https://tools.ietf.org/html/rfc5802), as needed by PostgreSQL. * * That is, only features used by PostgreSQL are implemented -- e.g., channel binding is not supported and * optional message fields omitted by PostgreSQL are not supported. */ -private[skunk] object Scram { +private[skunk] object Scram extends ScramPlatform { val SaslMechanism = "SCRAM-SHA-256" val NoChannelBinding = ByteVector.view("n,,".getBytes) @@ -26,11 +23,6 @@ private[skunk] object Scram { def bytesUtf8: ByteVector = ByteVector.view(value.getBytes(java.nio.charset.StandardCharsets.UTF_8)) } - def clientFirstBareWithRandomNonce: ByteVector = { - val nonce = ByteVector.view(crypto.randomBytes(32).asInstanceOf[Uint8Array]).toBase64 - clientFirstBareWithNonce(nonce) - } - def clientFirstBareWithNonce(nonce: String): ByteVector = s"n=,r=${nonce}".bytesUtf8 @@ -69,27 +61,6 @@ private[skunk] object Scram { } } - private val crypto = js.Dynamic.global.require("crypto") - - private def HMAC(key: ByteVector, str: ByteVector): ByteVector = { - val mac = crypto.createHmac("sha256", key.toUint8Array) - mac.update(str.toUint8Array) - ByteVector.view(mac.digest().asInstanceOf[Uint8Array]) - } - - private def H(input: ByteVector): ByteVector = { - val hash = crypto.createHash("sha256") - hash.update(input.toUint8Array) - ByteVector.view(hash.digest().asInstanceOf[Uint8Array]) - } - - private def Hi(str: String, salt: ByteVector, iterations: Int): ByteVector = { - // TODO It is unfortunate that we have to use a sync API here when an async is available - // To make the change here will require running an F[_]: Async up the hiearchy - val salted = crypto.pbkdf2Sync(str, salt.toUint8Array, iterations, 8 * 32, "sha256") - ByteVector.view(salted.asInstanceOf[Uint8Array]).take(32) - } - private def makeClientProofAndServerSignature(password: String, salt: ByteVector, iterations: Int, clientFirstMessageBare: ByteVector, serverFirstMessage: ByteVector, clientFinalMessageWithoutProof: ByteVector): (ClientProof, Verifier) = { val saltedPassword = Hi(SaslPrep.saslPrepStored(password), salt, iterations) val clientKey = HMAC(saltedPassword, "Client Key".bytesUtf8) diff --git a/modules/core/js/src/main/scala/net/protocol/StartupPlatform.scala b/modules/core/js-native/src/main/scala/protocol/StartupPlatform.scala similarity index 100% rename from modules/core/js/src/main/scala/net/protocol/StartupPlatform.scala rename to modules/core/js-native/src/main/scala/protocol/StartupPlatform.scala diff --git a/modules/core/js/src/main/scala/net/message/ScramPlatform.scala b/modules/core/js/src/main/scala/net/message/ScramPlatform.scala new file mode 100644 index 00000000..82c35517 --- /dev/null +++ b/modules/core/js/src/main/scala/net/message/ScramPlatform.scala @@ -0,0 +1,40 @@ +// Copyright (c) 2018-2021 by Rob Norris +// This software is licensed under the MIT License (MIT). +// For more information see LICENSE or https://opensource.org/licenses/MIT + +package skunk.net.message + +import scodec.bits.ByteVector + +import scala.scalajs.js +import scala.scalajs.js.typedarray.Uint8Array + +private[message] trait ScramPlatform { this: Scram.type => + + private val crypto = js.Dynamic.global.require("crypto") + + def clientFirstBareWithRandomNonce: ByteVector = { + val nonce = ByteVector.view(crypto.randomBytes(32).asInstanceOf[Uint8Array]).toBase64 + clientFirstBareWithNonce(nonce) + } + + private[message] def HMAC(key: ByteVector, str: ByteVector): ByteVector = { + val mac = crypto.createHmac("sha256", key.toUint8Array) + mac.update(str.toUint8Array) + ByteVector.view(mac.digest().asInstanceOf[Uint8Array]) + } + + private[message] def H(input: ByteVector): ByteVector = { + val hash = crypto.createHash("sha256") + hash.update(input.toUint8Array) + ByteVector.view(hash.digest().asInstanceOf[Uint8Array]) + } + + private[message] def Hi(str: String, salt: ByteVector, iterations: Int): ByteVector = { + // TODO It is unfortunate that we have to use a sync API here when an async is available + // To make the change here will require running an F[_]: Async up the hiearchy + val salted = crypto.pbkdf2Sync(str, salt.toUint8Array, iterations, 8 * 32, "sha256") + ByteVector.view(salted.asInstanceOf[Uint8Array]).take(32) + } + +} diff --git a/modules/core/native/src/main/scala-2/SqlState.scala b/modules/core/native/src/main/scala-2/SqlState.scala new file mode 100644 index 00000000..15f5e7f9 --- /dev/null +++ b/modules/core/native/src/main/scala-2/SqlState.scala @@ -0,0 +1,1424 @@ +// Copyright (c) 2018-2021 by Rob Norris +// This software is licensed under the MIT License (MIT). +// For more information see LICENSE or https://opensource.org/licenses/MIT + +package skunk + +import scala.collection.immutable.IndexedSeq +import skunk.exception.PostgresErrorException + +/** Enumerated type of Postgres error codes. See the companion object for more information. */ +sealed abstract class SqlState(val code: String) { + + def unapply(e: Throwable): Option[PostgresErrorException] = + Some(e).collect { case e: PostgresErrorException if e.code == code => e } + +} + +/** + * Enumerated type of Postgres error codes. These can be used as extractors for error handling, + * for example: + * {{{ + * doSomething.recoverWith { case SqlState.ForeignKeyViolation(ex) => ... } + * }}} + * @see [[https://www.postgresql.org/docs/10/errcodes-appendix.html PostgreSQL Error Codes]] + */ +object SqlState { + + /** + * SqlState `25001` + * @group Instances + */ + case object ActiveSqlTransaction extends SqlState("25001") + + /** + * SqlState `57P01` + * @group Instances + */ + case object AdminShutdown extends SqlState("57P01") + + /** + * SqlState `42P09` + * @group Instances + */ + case object AmbiguousAlias extends SqlState("42P09") + + /** + * SqlState `42702` + * @group Instances + */ + case object AmbiguousColumn extends SqlState("42702") + + /** + * SqlState `42725` + * @group Instances + */ + case object AmbiguousFunction extends SqlState("42725") + + /** + * SqlState `42P08` + * @group Instances + */ + case object AmbiguousParameter extends SqlState("42P08") + + /** + * SqlState `2202E` + * @group Instances + */ + case object ArraySubscriptError extends SqlState("2202E") + + /** + * SqlState `22P04` + * @group Instances + */ + case object BadCopyFileFormat extends SqlState("22P04") + + /** + * SqlState `25002` + * @group Instances + */ + case object BranchTransactionAlreadyActive extends SqlState("25002") + + /** + * SqlState `42846` + * @group Instances + */ + case object CannotCoerce extends SqlState("42846") + + /** + * SqlState `57P03` + * @group Instances + */ + case object CannotConnectNow extends SqlState("57P03") + + /** + * SqlState `55P02` + * @group Instances + */ + case object CantChangeRuntimeParam extends SqlState("55P02") + + /** + * SqlState `21000` + * @group Instances + */ + case object CardinalityViolation extends SqlState("21000") + + /** + * SqlState `20000` + * @group Instances + */ + case object CaseNotFound extends SqlState("20000") + + /** + * SqlState `22021` + * @group Instances + */ + case object CharacterNotInRepertoire extends SqlState("22021") + + /** + * SqlState `23514` + * @group Instances + */ + case object CheckViolation extends SqlState("23514") + + /** + * SqlState `F0000` + * @group Instances + */ + case object ConfigFileError extends SqlState("F0000") + + /** + * SqlState `08003` + * @group Instances + */ + case object ConnectionDoesNotExist extends SqlState("08003") + + /** + * SqlState `08000` + * @group Instances + */ + case object ConnectionException extends SqlState("08000") + + /** + * SqlState `08006` + * @group Instances + */ + case object ConnectionFailure extends SqlState("08006") + + /** + * SqlState `38001` + * @group Instances + */ + case object ContainingSqlNotPermitted extends SqlState("38001") + + /** + * SqlState `57P02` + * @group Instances + */ + case object CrashShutdown extends SqlState("57P02") + + /** + * SqlState `XX001` + * @group Instances + */ + case object DataCorrupted extends SqlState("XX001") + + /** + * SqlState `22000` + * @group Instances + */ + case object DataException extends SqlState("22000") + + /** + * SqlState `57P04` + * @group Instances + */ + case object DatabaseDropped extends SqlState("57P04") + + /** + * SqlState `42804` + * @group Instances + */ + case object DatatypeMismatch extends SqlState("42804") + + /** + * SqlState `22008` + * @group Instances + */ + case object DatetimeFieldOverflow extends SqlState("22008") + + /** + * SqlState `40P01` + * @group Instances + */ + case object DeadlockDetected extends SqlState("40P01") + + /** + * SqlState `2BP01` + * @group Instances + */ + case object DependentObjectsStillExist extends SqlState("2BP01") + + /** + * SqlState `2B000` + * @group Instances + */ + case object DependentPrivilegeDescriptorsStillExist extends SqlState("2B000") + + /** + * SqlState `01P01` + * @group Instances + */ + case object DeprecatedFeature extends SqlState("01P01") + + /** + * SqlState `53100` + * @group Instances + */ + case object DiskFull extends SqlState("53100") + + /** + * SqlState `22012` + * @group Instances + */ + case object DivisionByZero extends SqlState("22012") + + /** + * SqlState `42712` + * @group Instances + */ + case object DuplicateAlias extends SqlState("42712") + + /** + * SqlState `42701` + * @group Instances + */ + case object DuplicateColumn extends SqlState("42701") + + /** + * SqlState `42P03` + * @group Instances + */ + case object DuplicateCursor extends SqlState("42P03") + + /** + * SqlState `42P04` + * @group Instances + */ + case object DuplicateDatabase extends SqlState("42P04") + + /** + * SqlState `58P02` + * @group Instances + */ + case object DuplicateFile extends SqlState("58P02") + + /** + * SqlState `42723` + * @group Instances + */ + case object DuplicateFunction extends SqlState("42723") + + /** + * SqlState `42710` + * @group Instances + */ + case object DuplicateObject extends SqlState("42710") + + /** + * SqlState `42P05` + * @group Instances + */ + case object DuplicatePreparedStatement extends SqlState("42P05") + + /** + * SqlState `42P06` + * @group Instances + */ + case object DuplicateSchema extends SqlState("42P06") + + /** + * SqlState `42P07` + * @group Instances + */ + case object DuplicateTable extends SqlState("42P07") + + /** + * SqlState `0100C` + * @group Instances + */ + case object DynamicResultSetsReturned extends SqlState("0100C") + + /** + * SqlState `22005` + * @group Instances + */ + case object ErrorInAssignment extends SqlState("22005") + + /** + * SqlState `2200B` + * @group Instances + */ + case object EscapeCharacterConflict extends SqlState("2200B") + + /** + * SqlState `23P01` + * @group Instances + */ + case object ExclusionViolation extends SqlState("23P01") + + /** + * SqlState `38000` + * @group Instances + */ + case object ExternalRoutineException extends SqlState("38000") + + /** + * SqlState `39000` + * @group Instances + */ + case object ExternalRoutineInvocationException extends SqlState("39000") + + /** + * SqlState `0A000` + * @group Instances + */ + case object FeatureNotSupported extends SqlState("0A000") + + /** + * SqlState `22P01` + * @group Instances + */ + case object FloatingPointException extends SqlState("22P01") + + /** + * SqlState `23503` + * @group Instances + */ + case object ForeignKeyViolation extends SqlState("23503") + + /** + * SqlState `2F005` + * @group Instances + */ + case object FunctionExecutedNoReturnStatement extends SqlState("2F005") + + /** + * SqlState `42803` + * @group Instances + */ + case object GroupingError extends SqlState("42803") + + /** + * SqlState `25008` + * @group Instances + */ + case object HeldCursorRequiresSameIsolationLevel extends SqlState("25008") + + /** + * SqlState `01008` + * @group Instances + */ + case object ImplicitZeroBitPadding extends SqlState("01008") + + /** + * SqlState `25P02` + * @group Instances + */ + case object InFailedSqlTransaction extends SqlState("25P02") + + /** + * SqlState `25003` + * @group Instances + */ + case object InappropriateAccessModeForBranchTransaction extends SqlState("25003") + + /** + * SqlState `25004` + * @group Instances + */ + case object InappropriateIsolationLevelForBranchTransaction extends SqlState("25004") + + /** + * SqlState `42P18` + * @group Instances + */ + case object IndeterminateDatatype extends SqlState("42P18") + + /** + * SqlState `XX002` + * @group Instances + */ + case object IndexCorrupted extends SqlState("XX002") + + /** + * SqlState `22022` + * @group Instances + */ + case object IndicatorOverflow extends SqlState("22022") + + /** + * SqlState `42501` + * @group Instances + */ + case object InsufficientPrivilege extends SqlState("42501") + + /** + * SqlState `53000` + * @group Instances + */ + case object InsufficientResources extends SqlState("53000") + + /** + * SqlState `23000` + * @group Instances + */ + case object IntegrityConstraintViolation extends SqlState("23000") + + /** + * SqlState `XX000` + * @group Instances + */ + case object InternalError extends SqlState("XX000") + + /** + * SqlState `22015` + * @group Instances + */ + case object IntervalFieldOverflow extends SqlState("22015") + + /** + * SqlState `2201E` + * @group Instances + */ + case object InvalidArgumentForLogarithm extends SqlState("2201E") + + /** + * SqlState `22016` + * @group Instances + */ + case object InvalidArgumentForNthValueFunction extends SqlState("22016") + + /** + * SqlState `22014` + * @group Instances + */ + case object InvalidArgumentForNtileFunction extends SqlState("22014") + + /** + * SqlState `2201F` + * @group Instances + */ + case object InvalidArgumentForPowerFunction extends SqlState("2201F") + + /** + * SqlState `2201G` + * @group Instances + */ + case object InvalidArgumentForWidthBucketFunction extends SqlState("2201G") + + /** + * SqlState `28000` + * @group Instances + */ + case object InvalidAuthorizationSpecification extends SqlState("28000") + + /** + * SqlState `22P03` + * @group Instances + */ + case object InvalidBinaryRepresentation extends SqlState("22P03") + + /** + * SqlState `3D000` + * @group Instances + */ + case object InvalidCatalogName extends SqlState("3D000") + + /** + * SqlState `22018` + * @group Instances + */ + case object InvalidCharacterValueForCast extends SqlState("22018") + + /** + * SqlState `42611` + * @group Instances + */ + case object InvalidColumnDefinition extends SqlState("42611") + + /** + * SqlState `42P10` + * @group Instances + */ + case object InvalidColumnReference extends SqlState("42P10") + + /** + * SqlState `42P11` + * @group Instances + */ + case object InvalidCursorDefinition extends SqlState("42P11") + + /** + * SqlState `34000` + * @group Instances + */ + case object InvalidCursorName extends SqlState("34000") + + /** + * SqlState `24000` + * @group Instances + */ + case object InvalidCursorState extends SqlState("24000") + + /** + * SqlState `42P12` + * @group Instances + */ + case object InvalidDatabaseDefinition extends SqlState("42P12") + + /** + * SqlState `22007` + * @group Instances + */ + case object InvalidDatetimeFormat extends SqlState("22007") + + /** + * SqlState `22019` + * @group Instances + */ + case object InvalidEscapeCharacter extends SqlState("22019") + + /** + * SqlState `2200D` + * @group Instances + */ + case object InvalidEscapeOctet extends SqlState("2200D") + + /** + * SqlState `22025` + * @group Instances + */ + case object InvalidEscapeSequence extends SqlState("22025") + + /** + * SqlState `42830` + * @group Instances + */ + case object InvalidForeignKey extends SqlState("42830") + + /** + * SqlState `42P13` + * @group Instances + */ + case object InvalidFunctionDefinition extends SqlState("42P13") + + /** + * SqlState `0LP01` + * @group Instances + */ + case object InvalidGrantOperation extends SqlState("0LP01") + + /** + * SqlState `0L000` + * @group Instances + */ + case object InvalidGrantor extends SqlState("0L000") + + /** + * SqlState `22010` + * @group Instances + */ + case object InvalidIndicatorParameterValue extends SqlState("22010") + + /** + * SqlState `0F001` + * @group Instances + */ + case object InvalidLocatorSpecification extends SqlState("0F001") + + /** + * SqlState `42602` + * @group Instances + */ + case object InvalidName extends SqlState("42602") + + /** + * SqlState `42P17` + * @group Instances + */ + case object InvalidObjectDefinition extends SqlState("42P17") + + /** + * SqlState `22023` + * @group Instances + */ + case object InvalidParameterValue extends SqlState("22023") + + /** + * SqlState `28P01` + * @group Instances + */ + case object InvalidPassword extends SqlState("28P01") + + /** + * SqlState `42P14` + * @group Instances + */ + case object InvalidPreparedStatementDefinition extends SqlState("42P14") + + /** + * SqlState `42P19` + * @group Instances + */ + case object InvalidRecursion extends SqlState("42P19") + + /** + * SqlState `2201B` + * @group Instances + */ + case object InvalidRegularExpression extends SqlState("2201B") + + /** + * SqlState `0P000` + * @group Instances + */ + case object InvalidRoleSpecification extends SqlState("0P000") + + /** + * SqlState `2201W` + * @group Instances + */ + case object InvalidRowCountInLimitClause extends SqlState("2201W") + + /** + * SqlState `2201X` + * @group Instances + */ + case object InvalidRowCountInResultOffsetClause extends SqlState("2201X") + + /** + * SqlState `3B001` + * @group Instances + */ + case object InvalidSavepointSpecification extends SqlState("3B001") + + /** + * SqlState `42P15` + * @group Instances + */ + case object InvalidSchemaDefinition extends SqlState("42P15") + + /** + * SqlState `3F000` + * @group Instances + */ + case object InvalidSchemaName extends SqlState("3F000") + + /** + * SqlState `26000` + * @group Instances + */ + case object InvalidSqlStatementName extends SqlState("26000") + + /** + * SqlState `39001` + * @group Instances + */ + case object InvalidSqlstateReturned extends SqlState("39001") + + /** + * SqlState `42P16` + * @group Instances + */ + case object InvalidTableDefinition extends SqlState("42P16") + + /** + * SqlState `22P02` + * @group Instances + */ + case object InvalidTextRepresentation extends SqlState("22P02") + + /** + * SqlState `22009` + * @group Instances + */ + case object InvalidTimeZoneDisplacementValue extends SqlState("22009") + + /** + * SqlState `0B000` + * @group Instances + */ + case object InvalidTransactionInitiation extends SqlState("0B000") + + /** + * SqlState `25000` + * @group Instances + */ + case object InvalidTransactionState extends SqlState("25000") + + /** + * SqlState `2D000` + * @group Instances + */ + case object InvalidTransactionTermination extends SqlState("2D000") + + /** + * SqlState `2200C` + * @group Instances + */ + case object InvalidUseOfEscapeCharacter extends SqlState("2200C") + + /** + * SqlState `2200S` + * @group Instances + */ + case object InvalidXmlComment extends SqlState("2200S") + + /** + * SqlState `2200N` + * @group Instances + */ + case object InvalidXmlContent extends SqlState("2200N") + + /** + * SqlState `2200M` + * @group Instances + */ + case object InvalidXmlDocument extends SqlState("2200M") + + /** + * SqlState `2200T` + * @group Instances + */ + case object InvalidXmlProcessingInstruction extends SqlState("2200T") + + /** + * SqlState `58030` + * @group Instances + */ + case object IoError extends SqlState("58030") + + /** + * SqlState `0F000` + * @group Instances + */ + case object LocatorException extends SqlState("0F000") + + /** + * SqlState `F0001` + * @group Instances + */ + case object LockFileExists extends SqlState("F0001") + + /** + * SqlState `55P03` + * @group Instances + */ + case object LockNotAvailable extends SqlState("55P03") + + /** + * SqlState `2F002` + * @group Instances + */ + case object ModifyingSqlDataNotPermitted2F extends SqlState("2F002") + + /** + * SqlState `38002` + * @group Instances + */ + case object ModifyingSqlDataNotPermitted38 extends SqlState("38002") + + /** + * SqlState `2200G` + * @group Instances + */ + case object MostSpecificTypeMismatch extends SqlState("2200G") + + /** + * SqlState `42622` + * @group Instances + */ + case object NameTooLong extends SqlState("42622") + + /** + * SqlState `25P01` + * @group Instances + */ + case object NoActiveSqlTransaction extends SqlState("25P01") + + /** + * SqlState `25005` + * @group Instances + */ + case object NoActiveSqlTransactionForBranchTransaction extends SqlState("25005") + + /** + * SqlState `02001` + * @group Instances + */ + case object NoAdditionalDynamicResultSetsReturned extends SqlState("02001") + + /** + * SqlState `02000` + * @group Instances + */ + case object NoData extends SqlState("02000") + + /** + * SqlState `P0002` + * @group Instances + */ + case object NoDataFound extends SqlState("P0002") + + /** + * SqlState `22P06` + * @group Instances + */ + case object NonstandardUseOfEscapeCharacter extends SqlState("22P06") + + /** + * SqlState `2200L` + * @group Instances + */ + case object NotAnXmlDocument extends SqlState("2200L") + + /** + * SqlState `23502` + * @group Instances + */ + case object NotNullViolation extends SqlState("23502") + + /** + * SqlState `01003` + * @group Instances + */ + case object NullValueEliminatedInSetFunction extends SqlState("01003") + + /** + * SqlState `22002` + * @group Instances + */ + case object NullValueNoIndicatorParameter extends SqlState("22002") + + /** + * SqlState `22004` + * @group Instances + */ + case object NullValueNotAllowed extends SqlState("22004") + + /** + * SqlState `39004` + * @group Instances + */ + case object NullValueNotAllowed39 extends SqlState("39004") + + /** + * SqlState `22003` + * @group Instances + */ + case object NumericValueOutOfRange extends SqlState("22003") + + /** + * SqlState `55006` + * @group Instances + */ + case object ObjectInUse extends SqlState("55006") + + /** + * SqlState `55000` + * @group Instances + */ + case object ObjectNotInPrerequisiteState extends SqlState("55000") + + /** + * SqlState `57000` + * @group Instances + */ + case object OperatorIntervention extends SqlState("57000") + + /** + * SqlState `53200` + * @group Instances + */ + case object OutOfMemory extends SqlState("53200") + + /** + * SqlState `P0000` + * @group Instances + */ + case object PlpgsqlError extends SqlState("P0000") + + /** + * SqlState `01007` + * @group Instances + */ + case object PrivilegeNotGranted extends SqlState("01007") + + /** + * SqlState `01006` + * @group Instances + */ + case object PrivilegeNotRevoked extends SqlState("01006") + + /** + * SqlState `54000` + * @group Instances + */ + case object ProgramLimitExceeded extends SqlState("54000") + + /** + * SqlState `2F003` + * @group Instances + */ + case object ProhibitedSqlStatementAttempted2F extends SqlState("2F003") + + /** + * SqlState `38003` + * @group Instances + */ + case object ProhibitedSqlStatementAttempted38 extends SqlState("38003") + + /** + * SqlState `08P01` + * @group Instances + */ + case object ProtocolViolation extends SqlState("08P01") + + /** + * SqlState `57014` + * @group Instances + */ + case object QueryCanceled extends SqlState("57014") + + /** + * SqlState `P0001` + * @group Instances + */ + case object RaiseException extends SqlState("P0001") + + /** + * SqlState `25006` + * @group Instances + */ + case object ReadOnlySqlTransaction extends SqlState("25006") + + /** + * SqlState `2F004` + * @group Instances + */ + case object ReadingSqlDataNotPermitted2F extends SqlState("2F004") + + /** + * SqlState `38004` + * @group Instances + */ + case object ReadingSqlDataNotPermitted38 extends SqlState("38004") + + /** + * SqlState `42939` + * @group Instances + */ + case object ReservedName extends SqlState("42939") + + /** + * SqlState `23001` + * @group Instances + */ + case object RestrictViolation extends SqlState("23001") + + /** + * SqlState `3B000` + * @group Instances + */ + case object SavepointException extends SqlState("3B000") + + /** + * SqlState `25007` + * @group Instances + */ + case object SchemaAndDataStatementMixingNotSupported extends SqlState("25007") + + /** + * SqlState `40001` + * @group Instances + */ + case object SerializationFailure extends SqlState("40001") + + /** + * SqlState `08001` + * @group Instances + */ + case object SqlClientUnableToEstablishSqlConnection extends SqlState("08001") + + /** + * SqlState `2F000` + * @group Instances + */ + case object SqlRoutineException extends SqlState("2F000") + + /** + * SqlState `08004` + * @group Instances + */ + case object SqlServerRejectedEstablishmentOfSqlConnection extends SqlState("08004") + + /** + * SqlState `03000` + * @group Instances + */ + case object SqlStatementNotYetComplete extends SqlState("03000") + + /** + * SqlState `39P02` + * @group Instances + */ + case object SrfProtocolViolated extends SqlState("39P02") + + /** + * SqlState `40003` + * @group Instances + */ + case object StatementCompletionUnknown extends SqlState("40003") + + /** + * SqlState `54001` + * @group Instances + */ + case object StatementTooComplex extends SqlState("54001") + + /** + * SqlState `22026` + * @group Instances + */ + case object StringDataLengthMismatch extends SqlState("22026") + + /** + * SqlState `22001` + * @group Instances + */ + case object StringDataRightTruncation extends SqlState("22001") + + /** + * SqlState `01004` + * @group Instances + */ + case object StringDataRightTruncation01 extends SqlState("01004") + + /** + * SqlState `22011` + * @group Instances + */ + case object SubstringError extends SqlState("22011") + + /** + * SqlState `00000` + * @group Instances + */ + case object SuccessfulCompletion extends SqlState("00000") + + /** + * SqlState `42601` + * @group Instances + */ + case object SyntaxError extends SqlState("42601") + + /** + * SqlState `42000` + * @group Instances + */ + case object SyntaxErrorOrAccessRuleViolation extends SqlState("42000") + + /** + * SqlState `54023` + * @group Instances + */ + case object TooManyArguments extends SqlState("54023") + + /** + * SqlState `54011` + * @group Instances + */ + case object TooManyColumns extends SqlState("54011") + + /** + * SqlState `53300` + * @group Instances + */ + case object TooManyConnections extends SqlState("53300") + + /** + * SqlState `P0003` + * @group Instances + */ + case object TooManyRows extends SqlState("P0003") + + /** + * SqlState `40002` + * @group Instances + */ + case object TransactionIntegrityConstraintViolation extends SqlState("40002") + + /** + * SqlState `08007` + * @group Instances + */ + case object TransactionResolutionUnknown extends SqlState("08007") + + /** + * SqlState `40000` + * @group Instances + */ + case object TransactionRollback extends SqlState("40000") + + /** + * SqlState `39P01` + * @group Instances + */ + case object TriggerProtocolViolated extends SqlState("39P01") + + /** + * SqlState `09000` + * @group Instances + */ + case object TriggeredActionException extends SqlState("09000") + + /** + * SqlState `27000` + * @group Instances + */ + case object TriggeredDataChangeViolation extends SqlState("27000") + + /** + * SqlState `22027` + * @group Instances + */ + case object TrimError extends SqlState("22027") + + /** + * SqlState `42703` + * @group Instances + */ + case object UndefinedColumn extends SqlState("42703") + + /** + * SqlState `58P01` + * @group Instances + */ + case object UndefinedFile extends SqlState("58P01") + + /** + * SqlState `42883` + * @group Instances + */ + case object UndefinedFunction extends SqlState("42883") + + /** + * SqlState `42704` + * @group Instances + */ + case object UndefinedObject extends SqlState("42704") + + /** + * SqlState `42P02` + * @group Instances + */ + case object UndefinedParameter extends SqlState("42P02") + + /** + * SqlState `42P01` + * @group Instances + */ + case object UndefinedTable extends SqlState("42P01") + + /** + * SqlState `23505` + * @group Instances + */ + case object UniqueViolation extends SqlState("23505") + + /** + * SqlState `22024` + * @group Instances + */ + case object UnterminatedCString extends SqlState("22024") + + /** + * SqlState `22P05` + * @group Instances + */ + case object UntranslatableCharacter extends SqlState("22P05") + + /** + * SqlState `01000` + * @group Instances + */ + case object Warning extends SqlState("01000") + + /** + * SqlState `42P20` + * @group Instances + */ + case object WindowingError extends SqlState("42P20") + + /** + * SqlState `44000` + * @group Instances + */ + case object WithCheckOptionViolation extends SqlState("44000") + + /** + * SqlState `42809` + * @group Instances + */ + case object WrongObjectType extends SqlState("42809") + + /** + * SqlState `2200F` + * @group Instances + */ + case object ZeroLengthCharacterString extends SqlState("2200F") + + val values: IndexedSeq[SqlState] = Vector( + ActiveSqlTransaction, + AdminShutdown, + AmbiguousAlias, + AmbiguousColumn, + AmbiguousFunction, + AmbiguousParameter, + ArraySubscriptError, + BadCopyFileFormat, + BranchTransactionAlreadyActive, + CannotCoerce, + CannotConnectNow, + CantChangeRuntimeParam, + CardinalityViolation, + CaseNotFound, + CharacterNotInRepertoire, + CheckViolation, + ConfigFileError, + ConnectionDoesNotExist, + ConnectionException, + ConnectionFailure, + ContainingSqlNotPermitted, + CrashShutdown, + DataCorrupted, + DataException, + DatabaseDropped, + DatatypeMismatch, + DatetimeFieldOverflow, + DeadlockDetected, + DependentObjectsStillExist, + DependentPrivilegeDescriptorsStillExist, + DeprecatedFeature, + DiskFull, + DivisionByZero, + DuplicateAlias, + DuplicateColumn, + DuplicateCursor, + DuplicateDatabase, + DuplicateFile, + DuplicateFunction, + DuplicateObject, + DuplicatePreparedStatement, + DuplicateSchema, + DuplicateTable, + DynamicResultSetsReturned, + ErrorInAssignment, + EscapeCharacterConflict, + ExclusionViolation, + ExternalRoutineException, + ExternalRoutineInvocationException, + FeatureNotSupported, + FloatingPointException, + ForeignKeyViolation, + FunctionExecutedNoReturnStatement, + GroupingError, + HeldCursorRequiresSameIsolationLevel, + ImplicitZeroBitPadding, + InFailedSqlTransaction, + InappropriateAccessModeForBranchTransaction, + InappropriateIsolationLevelForBranchTransaction, + IndeterminateDatatype, + IndexCorrupted, + IndicatorOverflow, + InsufficientPrivilege, + InsufficientResources, + IntegrityConstraintViolation, + InternalError, + IntervalFieldOverflow, + InvalidArgumentForLogarithm, + InvalidArgumentForNthValueFunction, + InvalidArgumentForNtileFunction, + InvalidArgumentForPowerFunction, + InvalidArgumentForWidthBucketFunction, + InvalidAuthorizationSpecification, + InvalidBinaryRepresentation, + InvalidCatalogName, + InvalidCharacterValueForCast, + InvalidColumnDefinition, + InvalidColumnReference, + InvalidCursorDefinition, + InvalidCursorName, + InvalidCursorState, + InvalidDatabaseDefinition, + InvalidDatetimeFormat, + InvalidEscapeCharacter, + InvalidEscapeOctet, + InvalidEscapeSequence, + InvalidForeignKey, + InvalidFunctionDefinition, + InvalidGrantOperation, + InvalidGrantor, + InvalidIndicatorParameterValue, + InvalidLocatorSpecification, + InvalidName, + InvalidObjectDefinition, + InvalidParameterValue, + InvalidPassword, + InvalidPreparedStatementDefinition, + InvalidRecursion, + InvalidRegularExpression, + InvalidRoleSpecification, + InvalidRowCountInLimitClause, + InvalidRowCountInResultOffsetClause, + InvalidSavepointSpecification, + InvalidSchemaDefinition, + InvalidSchemaName, + InvalidSqlStatementName, + InvalidSqlstateReturned, + InvalidTableDefinition, + InvalidTextRepresentation, + InvalidTimeZoneDisplacementValue, + InvalidTransactionInitiation, + InvalidTransactionState, + InvalidTransactionTermination, + InvalidUseOfEscapeCharacter, + InvalidXmlComment, + InvalidXmlContent, + InvalidXmlDocument, + InvalidXmlProcessingInstruction, + IoError, + LocatorException, + LockFileExists, + LockNotAvailable, + ModifyingSqlDataNotPermitted2F, + ModifyingSqlDataNotPermitted38, + MostSpecificTypeMismatch, + NameTooLong, + NoActiveSqlTransaction, + NoActiveSqlTransactionForBranchTransaction, + NoAdditionalDynamicResultSetsReturned, + NoData, + NoDataFound, + NonstandardUseOfEscapeCharacter, + NotAnXmlDocument, + NotNullViolation, + NullValueEliminatedInSetFunction, + NullValueNoIndicatorParameter, + NullValueNotAllowed, + NullValueNotAllowed39, + NumericValueOutOfRange, + ObjectInUse, + ObjectNotInPrerequisiteState, + OperatorIntervention, + OutOfMemory, + PlpgsqlError, + PrivilegeNotGranted, + PrivilegeNotRevoked, + ProgramLimitExceeded, + ProhibitedSqlStatementAttempted2F, + ProhibitedSqlStatementAttempted38, + ProtocolViolation, + QueryCanceled, + RaiseException, + ReadOnlySqlTransaction, + ReadingSqlDataNotPermitted2F, + ReadingSqlDataNotPermitted38, + ReservedName, + RestrictViolation, + SavepointException, + SchemaAndDataStatementMixingNotSupported, + SerializationFailure, + SqlClientUnableToEstablishSqlConnection, + SqlRoutineException, + SqlServerRejectedEstablishmentOfSqlConnection, + SqlStatementNotYetComplete, + SrfProtocolViolated, + StatementCompletionUnknown, + StatementTooComplex, + StringDataLengthMismatch, + StringDataRightTruncation, + StringDataRightTruncation01, + SubstringError, + SuccessfulCompletion, + SyntaxError, + SyntaxErrorOrAccessRuleViolation, + TooManyArguments, + TooManyColumns, + TooManyConnections, + TooManyRows, + TransactionIntegrityConstraintViolation, + TransactionResolutionUnknown, + TransactionRollback, + TriggerProtocolViolated, + TriggeredActionException, + TriggeredDataChangeViolation, + TrimError, + UndefinedColumn, + UndefinedFile, + UndefinedFunction, + UndefinedObject, + UndefinedParameter, + UndefinedTable, + UniqueViolation, + UnterminatedCString, + UntranslatableCharacter, + Warning, + WindowingError, + WithCheckOptionViolation, + WrongObjectType, + ZeroLengthCharacterString, + ) + +} \ No newline at end of file diff --git a/modules/core/native/src/main/scala-2/codec/EnumCodecPlatform.scala b/modules/core/native/src/main/scala-2/codec/EnumCodecPlatform.scala new file mode 100644 index 00000000..20674360 --- /dev/null +++ b/modules/core/native/src/main/scala-2/codec/EnumCodecPlatform.scala @@ -0,0 +1,8 @@ +// Copyright (c) 2018-2021 by Rob Norris +// This software is licensed under the MIT License (MIT). +// For more information see LICENSE or https://opensource.org/licenses/MIT + +package skunk +package codec + +trait EnumCodecPlatform diff --git a/modules/core/native/src/main/scala/net/message/PasswordMessagePlatform.scala b/modules/core/native/src/main/scala/net/message/PasswordMessagePlatform.scala new file mode 100644 index 00000000..e5fca60b --- /dev/null +++ b/modules/core/native/src/main/scala/net/message/PasswordMessagePlatform.scala @@ -0,0 +1,72 @@ +// Copyright (c) 2018-2021 by Rob Norris +// This software is licensed under the MIT License (MIT). +// For more information see LICENSE or https://opensource.org/licenses/MIT + +package skunk.net.message + +import scodec.bits.ByteVector + +import scala.scalanative.unsafe._ +import scala.scalanative.unsigned._ + +import openssl._ + +private[message] trait PasswordMessagePlatform { + + // See https://www.postgresql.org/docs/9.6/protocol-flow.html#AEN113418 + // and https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/util/MD5Digest.java + def md5(user: String, password: String, salt: Array[Byte]): PasswordMessage = Zone { implicit z => + + // Hash with this thing + val ctx = EVP_MD_CTX_new() + if (ctx == null) + throw new RuntimeException("EVP_MD_CTX_new") + + val `type` = EVP_get_digestbyname(c"MD5") + if (`type` == null) + throw new RuntimeException("EVP_get_digestbyname") + + try { + + val md = stackalloc[Byte](EVP_MAX_MD_SIZE) + val size = stackalloc[CUnsignedInt]() + + // First round + if (EVP_DigestInit_ex(ctx, `type`, null) != 1) + throw new RuntimeException("EVP_DigestInit_ex") + if (EVP_DigestUpdate(ctx, toCString(password), password.length.toULong) != 1) + throw new RuntimeException("EVP_DigestUpdate") + if (EVP_DigestUpdate(ctx, toCString(user), user.length.toULong) != 1) + throw new RuntimeException("EVP_DigestUpdate") + if (EVP_DigestFinal_ex(ctx, md, size) != 1) + throw new RuntimeException("EVP_DigestFinal_ex") + var hex = BigInt(1, ByteVector.view(md, (!size).toLong).toArray).toString(16) + while (hex.length < 32) + hex = "0" + hex + + if (EVP_MD_CTX_reset(ctx) != 1) + throw new RuntimeException("EVP_MD_CTX_reset") + + // Second round + if (EVP_DigestInit_ex(ctx, `type`, null) != 1) + throw new RuntimeException("EVP_DigestInit_ex") + if (EVP_DigestUpdate(ctx, toCString(hex), 32.toULong) != 1) + throw new RuntimeException("EVP_DigestUpdate") + if (EVP_DigestUpdate(ctx, ByteVector.view(salt).toPtr, salt.length.toULong) != 1) + throw new RuntimeException("EVP_DigestUpdate") + if (EVP_DigestFinal_ex(ctx, md, size) != 1) + throw new RuntimeException("EVP_DigestFinal_ex") + hex = BigInt(1, ByteVector.view(md, (!size).toLong).toArray).toString(16) + while (hex.length < 32) + hex = "0" + hex + + // Done + new PasswordMessage("md5" + hex) {} + + } finally { + openssl.EVP_MD_CTX_free(ctx) + } + + } + +} diff --git a/modules/core/native/src/main/scala/net/message/ScramPlatform.scala b/modules/core/native/src/main/scala/net/message/ScramPlatform.scala new file mode 100644 index 00000000..b19eb2f4 --- /dev/null +++ b/modules/core/native/src/main/scala/net/message/ScramPlatform.scala @@ -0,0 +1,56 @@ +// Copyright (c) 2018-2021 by Rob Norris +// This software is licensed under the MIT License (MIT). +// For more information see LICENSE or https://opensource.org/licenses/MIT + +package skunk.net.message + +import scodec.bits.ByteVector + +import scala.scalanative.unsafe._ +import scala.scalanative.unsigned._ + +import openssl._ + +private[message] trait ScramPlatform { this: Scram.type => + + def clientFirstBareWithRandomNonce: ByteVector = { + val buf = stackalloc[Byte](32) + if (RAND_bytes(buf, 32) != 1) + throw new RuntimeException("RAND_bytes") + val nonce = ByteVector.view(buf, 32).toBase64 + clientFirstBareWithNonce(nonce) + } + + private[message] def HMAC(key: ByteVector, str: ByteVector): ByteVector = Zone { implicit z => + val evpMd = EVP_get_digestbyname(c"SHA256") + if (evpMd == null) + throw new RuntimeException("EVP_get_digestbyname") + val md = stackalloc[Byte](EVP_MAX_MD_SIZE) + val mdLen = stackalloc[CUnsignedInt]() + if (openssl.HMAC(evpMd, key.toPtr, key.size.toInt, str.toPtr, str.size.toULong, md, mdLen) == null) + throw new RuntimeException("HMAC") + ByteVector.fromPtr(md.asInstanceOf[Ptr[Byte]], (!mdLen).toLong) + } + + private[message] def H(input: ByteVector): ByteVector = Zone { implicit z => + val md = stackalloc[Byte](EVP_MAX_MD_SIZE) + val size = stackalloc[CUnsignedInt]() + val `type` = EVP_get_digestbyname(c"SHA256") + if (`type` == null) + throw new RuntimeException("EVP_get_digestbyname") + if (EVP_Digest(input.toPtr, input.size.toULong, md, size, `type`, null) != 1) + throw new RuntimeException("EVP_Digest") + ByteVector.fromPtr(md, (!size).toLong) + } + + private[message] def Hi(str: String, salt: ByteVector, iterations: Int): ByteVector = Zone { implicit z => + val digest = EVP_get_digestbyname(c"SHA256") + if (digest == null) + throw new RuntimeException("EVP_get_digestbyname") + val out = stackalloc[Byte](32) + if (PKCS5_PBKDF2_HMAC(toCString(str), str.length, salt.toPtr, salt.size.toInt, iterations, digest, 32, out) != 1) + throw new RuntimeException("PKCS5_PBKDF2_HMAC") + ByteVector.fromPtr(out, 32) + } + +} diff --git a/modules/core/native/src/main/scala/net/message/openssl.scala b/modules/core/native/src/main/scala/net/message/openssl.scala new file mode 100644 index 00000000..4efc9273 --- /dev/null +++ b/modules/core/native/src/main/scala/net/message/openssl.scala @@ -0,0 +1,63 @@ +// Copyright (c) 2018-2021 by Rob Norris +// This software is licensed under the MIT License (MIT). +// For more information see LICENSE or https://opensource.org/licenses/MIT + +package skunk.net.message + +import scala.scalanative.unsafe._ + +@link("crypto") +@extern +private[message] object openssl { + + final val EVP_MAX_MD_SIZE = 64 + + type EVP_MD + type EVP_MD_CTX + type ENGINE + + def EVP_get_digestbyname(name: Ptr[CChar]): Ptr[EVP_MD] = extern + + def EVP_MD_CTX_new(): Ptr[EVP_MD_CTX] = extern + def EVP_MD_CTX_reset(ctx: Ptr[EVP_MD_CTX]): CInt = extern + def EVP_MD_CTX_free(ctx: Ptr[EVP_MD_CTX]): Unit = extern + + def EVP_DigestInit_ex(ctx: Ptr[EVP_MD_CTX], `type`: Ptr[EVP_MD], impl: Ptr[ENGINE]): CInt = extern + def EVP_DigestUpdate(ctx: Ptr[EVP_MD_CTX], d: Ptr[Byte], cnt: CSize): CInt = extern + def EVP_DigestFinal_ex(ctx: Ptr[EVP_MD_CTX], md: Ptr[Byte], s: Ptr[CUnsignedInt]): CInt = extern + def EVP_Digest( + data: Ptr[Byte], + count: CSize, + md: Ptr[Byte], + size: Ptr[CUnsignedInt], + `type`: Ptr[EVP_MD], + impl: Ptr[ENGINE] + ): CInt = extern + + def HMAC( + evp_md: Ptr[EVP_MD], + key: Ptr[Byte], + key_len: Int, + d: Ptr[Byte], + n: CSize, + md: Ptr[Byte], + md_len: Ptr[CUnsignedInt] + ): Ptr[CUnsignedChar] = extern + + def PKCS5_PBKDF2_HMAC( + pass: Ptr[CChar], + passlen: CInt, + salt: Ptr[Byte], + saltlen: CInt, + iter: CInt, + digest: Ptr[EVP_MD], + keylen: CInt, + out: Ptr[Byte] + ): CInt = extern + + def RAND_bytes( + buf: Ptr[CChar], + num: CInt + ): CInt = extern + +} diff --git a/modules/tests/shared/src/test/scala-2/codec/EnumCodecTest.scala b/modules/tests/js-jvm/src/test/scala-2/codec/EnumCodecTest.scala similarity index 100% rename from modules/tests/shared/src/test/scala-2/codec/EnumCodecTest.scala rename to modules/tests/js-jvm/src/test/scala-2/codec/EnumCodecTest.scala diff --git a/modules/tests/jvm/src/main/scala/ffstest/FFrameworkPlatform.scala b/modules/tests/jvm/src/main/scala/ffstest/FFrameworkPlatform.scala index 915ff897..16acda01 100644 --- a/modules/tests/jvm/src/main/scala/ffstest/FFrameworkPlatform.scala +++ b/modules/tests/jvm/src/main/scala/ffstest/FFrameworkPlatform.scala @@ -6,20 +6,4 @@ package ffstest import munit.CatsEffectSuite -import java.util.concurrent.Executors -import scala.concurrent.ExecutionContext - -trait FTestPlatform extends CatsEffectSuite { - - // ensure that we have bountiful threads - val executor = Executors.newCachedThreadPool() - - override val munitExecutionContext: ExecutionContext = - ExecutionContext.fromExecutor(executor) - - override def afterAll(): Unit = { - super.afterAll(); - executor.shutdown() - } - -} +trait FTestPlatform extends CatsEffectSuite diff --git a/modules/tests/native/src/main/scala/ffstest/FFrameworkPlatform.scala b/modules/tests/native/src/main/scala/ffstest/FFrameworkPlatform.scala new file mode 100644 index 00000000..d1db0352 --- /dev/null +++ b/modules/tests/native/src/main/scala/ffstest/FFrameworkPlatform.scala @@ -0,0 +1,12 @@ +// Copyright (c) 2018-2021 by Rob Norris +// This software is licensed under the MIT License (MIT). +// For more information see LICENSE or https://opensource.org/licenses/MIT + +package ffstest + +import epollcat.unsafe.EpollRuntime +import munit.CatsEffectSuite + +trait FTestPlatform extends CatsEffectSuite { + override def munitIORuntime = EpollRuntime.global +} \ No newline at end of file diff --git a/modules/tests/shared/src/test/scala/StartupTest.scala b/modules/tests/shared/src/test/scala/StartupTest.scala index c43074f3..21beec06 100644 --- a/modules/tests/shared/src/test/scala/StartupTest.scala +++ b/modules/tests/shared/src/test/scala/StartupTest.scala @@ -5,13 +5,14 @@ package tests import cats.effect._ -import com.comcast.ip4s.UnknownHostException import fs2.io.net.ConnectException import natchez.Trace.Implicits.noop import skunk._ import skunk.exception.SkunkException import skunk.exception.StartupException +import java.io.IOException + class StartupTest extends ffstest.FTest { // Different ports for different authentication schemes. @@ -253,6 +254,6 @@ class StartupTest extends ffstest.FTest { host = "blergh", user = "bob", database = "nobody cares", - ).use(_ => IO.unit).assertFailsWith[UnknownHostException] + ).use(_ => IO.unit).assertFailsWith[IOException] // ideally an `UnknownHostException` } } diff --git a/modules/tests/shared/src/test/scala-2/codec/TemporalCodecTest.scala b/modules/tests/shared/src/test/scala/codec/TemporalCodecTest.scala similarity index 98% rename from modules/tests/shared/src/test/scala-2/codec/TemporalCodecTest.scala rename to modules/tests/shared/src/test/scala/codec/TemporalCodecTest.scala index d4222fef..5ba93846 100644 --- a/modules/tests/shared/src/test/scala-2/codec/TemporalCodecTest.scala +++ b/modules/tests/shared/src/test/scala/codec/TemporalCodecTest.scala @@ -7,7 +7,7 @@ package codec import cats.Eq import cats.syntax.all._ -import io.chrisdavenport.cats.time.{ offsetdatetimeInstances => _, _ } +import org.typelevel.cats.time.{ offsetdatetimeInstances => _, _ } import java.time._ import skunk.codec.temporal._ import cats.effect.{IO, Resource} diff --git a/project/plugins.sbt b/project/plugins.sbt index 2af37fc5..d748933b 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -11,3 +11,6 @@ addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.4") addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.3.6") addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.6") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.11.0") +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.4.7") +addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "1.2.0") +addSbtPlugin("com.armanbilge" % "sbt-scala-native-config-brew-github-actions" % "0.1.2")