Click here to Skip to main content
15,886,963 members
Articles / Internet of Things

VisionFive 2 RISC-V - Setting up Apache2, Php, Postgres, Mosquitto, and Compilers

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
16 Dec 2023CPOL21 min read 4.9K  
Creating a simple VisionFive 2 RISC-V SBC web site using Apache2, PHP, and Postgres with the Mosquitto message broker and installing Golang, Java, and Rust.
Installing the software needed to create a website on a VisionFive 2 RISC-V SBC and exploring the technologies of Apache2, PHP, and PostgreSQL under Debian on the device. Add an investigation into the Mosquitto message broker which uses the MQTT protocol to allow edge devices to publish messages to subscribers. Add in an investigation into programming languages including Golang, Java, and Rust.

Contents

Introduction

The VisionFive 2 SBC is similar to the Raspberry Pi 4 in size and capabilities though unlike the Raspberry Pi 4 which uses ARM processor technology, the VisionFive 2 with its JH7110 processor uses RISC-V processor technology. The VisionFive 2 does not have a large support community and finding assistance and documentation on the internet with architecture specific issues can be difficult and time consuming.

Since the RISC-V processor technology is fairly new with a much smaller portfolio of devices, the variety and robustness of software available for the RISC-V is not as large nor as diverse as for the Raspberry Pi 4 especially in the area of IoT. Fortunately, there are a large body of applications which depend on a C/C++ toolchain in some fashion and so long as that toolchain for the RISC-V is correct, then the applications that are built from that toolchain tend to be reliable.

The one area of glaring weakness appears to be the GPU firmware which means that graphical applications such as web browsers may tend to have issues until the GPU firmware and the various levels of the graphics stack become more robust and reliable.

However, the Apache2 HTTP web server as well as PHP script language and the PostgreSQL database engine are available as RISC-V builds and can be installed on a Debian OS with the VisionFive 2 using apt install. Naturally, I was curious and decided to try making the VisionFive 2 I recently purchased into a web server with a simple website using LAMP like technologies of Apache2, PHP, with PostgreSQL as the database engine. I decided on PostgreSQL over MySQL as I found a brief article that compared several database engines compiled for RISC-V and PostgreSQL was reported to be more stable.

I also wanted to include some experiments with message brokers running on the VisionFive 2. There are several different message broker protocols and I decided to start with the Eclipse project Mosquitto. Mosquitto uses a publish/subscribe model in which clients publish messages to a particular topic and other clients subscribe to the topic in order to receive those messages.

Finally, I was curious about programming languages available and how those seem to work with a simple application.

Background

For a background on my initial work with my VisionFive 2, I recommend the previous article I wrote, Setting Up a New VisionFive 2 RISC-V SBC, that describes the unboxing and exploration of capabilities of the device. One important topic in that article was addressing a file space issue I discovered with a 64 GB microSD card having a file space of only 3.2 GB. In that article, I describe using the parted and resize2fs utilities of Debian to resize the partition containing the file system to extend it, in my case from 3.2 GB to almost 64 GB.

Software Installation and Setup

The software packages of interest are all available for installation via apt though in some cases an initial package installation is followed by using some other tool to install additional capabilities. In some cases, configuration files need to be modified by hand after installation.

Apache Installation and Setup

The Apache2 installation went smoothly and the installation script seemed to take care of everything needed. I was able to test the Apache2 web server by using a browser on a Windows PC with a URL of http://starfive/ and the default Apache2 test page displayed.

Shell
sudo apt install apache2

The web server directory where Apache2 looks for web pages when it is given a URL is /var/www/html. One of the first things I did was to create a symbolic link from my home directory to /var/www/html in order to make it easy for me to access it.

Configuration files and directories for Apache2 are located in /etc/apache2. Should you decide to have additional services through the Apache2 web server, you will need to modify files in the directory tree whose root is /etc/apache2. For some services, you will need to install additional packages as well. See Digital Ocean: How To Configure the Apache Web Server on an Ubuntu or Debian VPS for an overview with some details about the files and directory structure used with Apache2.

There are several Apache2 service management commands that are useful:

  • sudo systemctl status apache2 display the current status of the service
  • sudo systemctl restart apache2 restart the service, often used after configuration file changes
  • sudo systemctl start apache2 start the service, rarely used since Apache2 starts at boot time
  • sudo systemctl stop apache2 stop the service

PHP Installation and Setup

The PHP installation also went smoothly. I installed both PHP and the Apache2 mod to allow using PHP scripts with either the Apache2 web server or on the command line.

Shell
sudo apt install php php-cli libapache2-mod-php

A quick version check with php --version showed PHP 8.1.12 (cli) (built: Nov 10 2022 07:28:34) (NTS).

After installing PHP, I tested a quick PHP script to check that it worked. The script was in a file test.php with the following source. The first line causes the script to be executed by the PHP interpreter so it contains the pound sign (#) followed by an exclamation point (!) that informs the shell that this is a file to be executed by the program whose path follows the exclamation point, in this case, the PHP interpreter located in /usr/bin.

PHP
#!/usr/bin/php
<?php
print "hello world\n"
?>

I used vi text editor to create the file and the chmod command to make the file test.php executable then executed the file with ./test.php since the file to be executed was in the current directory. The script generated the expected output.

user@starfive:~/Documents/github/web/phpdb$ vi test.php
user@starfive:~/Documents/github/web/phpdb$ chmod +x test.php
user@starfive:~/Documents/github/web/phpdb$ ./test.php
hello world
user@starfive:~/Documents/github/web/phpdb$

Next, I tried a simple PHP script in the Apache2 HTML folder to test that PHP worked with Apache2. The test was to display a page using the PHP built in function phpinfo() to display a web page containing the various PHP settings. The URL used in the browser was http://starfive/first.php.

user@starfive:~/Documents/webserver$ vi first.php
user@starfive:~/Documents/webserver$ cat first.php
<?php
phpinfo();
?>
user@starfive:~/Documents/webserver$ 

PostgreSQL Installation and Setup

I found the installation and setup of PostgreSQL the most complex of these services. In fact, I had to apt remove the packages of my first installation attempt because I seemed to have made a mistake that resulted in blocking further progress. The second attempt to install PostgreSQL went fairly smoothly as I had made enough mistakes resulting in learning.

The various programming languages had their own libraries or packages to be installed for accessing the PostgreSQL service and performing database operations. Most have more than one with several languages having one or more versions of an Object Relationship Mapping (ORM) software that was on top of the standard database connection and SQL statement execution library.

A mistake I made when setting up the operational environment was not understanding the use of the psql utility and how the pg_hba.conf configuration file affected user roles. I spent a lot of time bouncing about from post to post and article to article, each of which provided fragments of the necessary knowledge and understanding.

The following is not meant to be a definitive guide to PostgreSQL but rather a procedure that I used to allow me to have the PostgreSQL database engine serving as a repository for a simple database that I could access using PHP to build web pages on the fly.

At some points during the installation and setup, the PostgreSQL service may need to be restarted. To restart a service, use the service command specifying the option to either stop or start the PostgreSQL service. The most common time to have to restart the PostgreSQL service is when a change is made to a configuration file such as /etc/postgresql/15/main/pg_hba.conf.

Shell
sudo service postgresql stop
sudo service postgresql start

There are also times when you need to use the psql utility that is installed as part of install PostgreSQL to make changes or to check or modify PostgreSQL engine data such as user/role settings, databases or tables, or to see the data within a table. The default superuser role/account created at the time of installation is postgres so the procedure is to run the psql utility with sudo as user postgres.

Shell
sudo -u postgres psql

A Brief Introduction to the psql Utility

The psql utility allows the use of SQL statements to perform queries and other actions supported by the SQL language. It also has a set of commands that are not SQL and these commands require that they begin with the backslash in order for the psql utility to know that the command is not an SQL statement but rather a psql utility command.

A few of the more useful psql backslash commands:

  • \du - describe or list all users
  • \l - list all databases
  • \c dbn - connect to database named dbn
  • \dv - describe or list all views
  • \dt - describe or list all tables, must be connected to a database
  • \d [tn] - describe table named tn with column details, must be connected to a database
  • \d+ [tn] - describe additional details for table named tn, must be connected to a database
  • \q - quit or exit the psql utility

SQL commands can be used from the psql command line. The most useful are SQL commands to CREATE roles, ALTER roles, and GRANT permissions to roles. SQL commands must be terminated with a semicolon (;) while backslash commands are not.

The psql utility is used to add or modify users/roles, an action which may also require a modification to the pg_hba.conf configuration file if the role being adding requires some special treatment. Changes to the configuration file should be followed by restarting the PostgreSQL service.

PostgreSQL engine management is done with a superuser role such as postgres. Normal user roles may have some of the privileges of a superuser role assigned to it, however a superuser account has all of the privileges unless the privileges are removed with ALTER or GRANT.

A Brief Overview of the Installation Procedure

The first task is to use sudo apt install to install first the PostgreSQL database engine and secondly, the PHP drivers needed for PHP programs to use the engine. Other programming languages will tend to have their own version of drivers for PostgreSQL such as JDBC drivers for Java, a PostgreSQL crate for rust, etc.

Shell
sudo apt-get install postgresql postgresql-client postgresql-client-common postgresql-common postgresql-contrib
sudo apt install php-pgsql

A mistake I made was to attempt to use PHP PEAR at the beginning. I ran into script errors from installed PEAR components. From my very limited experience, it appeared that some of the PEAR material was PHP 5 code using functionality deprecated in PHP 8. I have found the PostgreSQL specific interface functions in package php-pgsql to work fine.

After installing the PostgreSQL packages, use the psql utility to create a couple of users/roles. I created two different roles, one named user which is the default user name of the VisionFive 2 Debian OS image and one named php to use with PHP web applications served by the Apache2 web server. I later added an additional user/role, golang with a password of golang, to use with the PostgreSQL query application that I wrote in Go when I had problems using the php username with no password.

With this installation, you get the PostgreSQL database engine running as a service along with a number of helpful command line utilities.

Mosquitto Installation and Setup

With Mosquitto, we are interested in using several components. First of all, we need the actual message broker server itself which provides the central point for publisher and subscriber clients to meet. The Mosquitto command line MQTT clients can be useful and we need the development components so that we can develop our own client applications.

Shell
sudo apt install mosquitto mosquitto-clients mosquitto-dev

In addition to the files needed for the Mosquitto message broker, there are two other packages that are used with the example C source file for MQTT message broker client. We use the JSON library so that we can send/receive JSON text messages between publisher and subscriber clients. For persistent store by the subscriber, we are using the SQLite3 embedded database.

The first is the libfastjson JSON parser library and the other is the SQLite3 embedded database engine.

Shell
sudo apt-get install libfastjson-dev libsqlite3-dev

The Mosquitto message broker runs as a service and is started up when Linux is starting up and initializing.

Programming Languages Found

I have found a number of programming language packages available on the VisionFive 2 with the Debian desktop. In addition to Python3, C/C++ and PHP, I've also found Go, Rust, and Java.

Python3 seems to be part of the image however the others needed to be installed. Installing gcc for C/C++ was straightforward as was installing golang. Installing Java was a bit more complex so I have provided a section on installing and setting up that programming language.

Golang install

There is a golang package available through the apt command so the easiest way to install Golang is to use sudo apt install golang.

This document explains the steps to setup the Golang environment and to write your first Hello World application, Tutorial: Get started with Go.

There is a bit of an interesting parallel with rust in that there is a go mod init command to create and initialize a go source module somewhat similar to the rust cargo.

Golang with PostgreSQL

Here is the example program to access the PostgreSQL database table with Go. You can test it with go run. I tried using the PHP PostgreSQL user/role which does not require a password. However, I could not figure out how to do without the password so I ended up creating a new user/role, golang with a password of golang, in order to test this simple query application.

Go
package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
)

// In order to allow this program to access the database and table
// use the psql utility of PostgreSQL to add the user and to grant
// access to the specified database and table.
//    sudo -u postgres psql
//    create user golang with password 'golang';
//    \c dbtest
//    grant select on phonebook to golang;

const (
    host     = "localhost"
    port     = 5432
    user     = "golang"
    password = "golang"
    dbname   = "dbtest"
)

func main() {
        // connection string
    psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)

        // open database
    db, err := sql.Open("postgres", psqlconn)
    CheckError(err)

        rows, err := db.Query(`SELECT "firstname", "lastname" FROM "phonebook"`)
        CheckError(err)

        defer rows.Close()
        for rows.Next() {
                var firstname string
                var lastname string

                err = rows.Scan(&firstname, &lastname)
                CheckError(err)

                fmt.Println(firstname, lastname)
        }

        // close database
    defer db.Close()

        // check db
    err = db.Ping()
    CheckError(err)

    fmt.Println("Connected!")
}

func CheckError(err error) {
    if err != nil {
        panic(err)
    }
}

Java install

After seeing a post on Reddit in the RISC-V sub-Reddit about performance problems with openJDK-19 or earlier on the RISC-V platform, I decided to investigate Java on the VisionFive 2. As of this date, 15th December 2023, it looks like openJDK-21 with the Hotspot JIT is available.

When I attempted to install sudo apt install openjdk-21-jre, error messages were displayed during the package installation:

Setting up ca-certificates-java (20220719) ...
Exception in thread "main" java.lang.InternalError: Error loading java.security                                      file
        at java.base/java.security.Security.initialize(Security.java:105)
        at java.base/java.security.Security.lambda$static$0(Security.java:84)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:319)
        at java.base/java.security.Security.<clinit>(Security.java:83)

followed by a number of error processing package errors and ending with:

Errors were encountered while processing:
ca-certificates-java
openjdk-21-jre-headless:riscv64
openjdk-21-jre:riscv64
openjdk-21-jdk-headless:riscv64
openjdk-21-jdk:riscv64
E: Sub-process /usr/bin/dpkg returned an error code (1)
user@starfive:/$

I ran into similar errors when I tried to install sudo apt install openjdk-21-jdk and sudo apt install openjdk-21-jre-headless. Searching, I found this post describing a similar problem, Bug#1030129: ca-certificates-java - Fails to install with OpenJDK 21: Error loading java.security file, and one person responded with a solution which I tried, sudo apt install ca-certificates-java default-jdk openjdk-21-jdk.

This last apt command line seemed to work fine and I did not see any errors. When I tried the java compiler with java --version, it reported the following:

user@starfive:/$ java --version
openjdk 21-ea 2023-09-19
OpenJDK Runtime Environment (build 21-ea+3-Debian-1)
OpenJDK 64-Bit Server VM (build 21-ea+3-Debian-1, mixed mode, sharing)
user@starfive:/$

Per this Digital Ocean article How to install Java with a section titled Step 2: Managing Java, I then checked the Java versions and the default version used with sudo update-alternatives --config java and sudo update-alternatives --config javac. I received the following output:

user@starfive:/$ sudo update-alternatives --config java
[sudo] password for user:
There are 2 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                           Priority   Status
------------------------------------------------------------
* 0            /usr/lib/jvm/java-21-openjdk-riscv64/bin/java   2111      auto mode
  1            /usr/lib/jvm/java-17-openjdk-riscv64/bin/java   1704      manual mode
  2            /usr/lib/jvm/java-21-openjdk-riscv64/bin/java   2111      manual mode

Press <enter> to keep the current choice[*], or type selection number:
user@starfive:/$ sudo update-alternatives --config javac
There are 2 choices for the alternative javac (providing /usr/bin/javac).

  Selection    Path                                            Priority   Status
------------------------------------------------------------
* 0            /usr/lib/jvm/java-21-openjdk-riscv64/bin/javac   2111      auto mode
  1            /usr/lib/jvm/java-17-openjdk-riscv64/bin/javac   1704      manual mode
  2            /usr/lib/jvm/java-21-openjdk-riscv64/bin/javac   2111      manual mode

Press <enter> to keep the current choice[*], or type selection number:
user@starfive:/$

See also the section Step 3: Setting the JAVA_HOME Environment Variable about adding the JAVA_HOME environment variable to the /etc/environment file so that Java applications depending on it will find the correct Java Virtual Machine.

From my installation I used the which command and the ls -l command to check where the java command came from:

user@starfive:/$ ls -l `which java`
lrwxrwxrwx 1 root root 22 Dec 22  2022 /usr/bin/java -> /etc/alternatives/java
user@starfive:/$ ls /etc/alternatives/java
/etc/alternatives/java
user@starfive:/$ ls -l /etc/alternatives/java
lrwxrwxrwx 1 root root 45 Dec 22  2022 /etc/alternatives/java -> /usr/lib/jvm/java-21-openjdk-riscv64/bin/java
user@starfive:/$ ls -l `which javac`
lrwxrwxrwx 1 root root 23 Dec 22  2022 /usr/bin/javac -> /etc/alternatives/javac
user@starfive:/$ ls -l /etc/alternatives/javac
lrwxrwxrwx 1 root root 46 Dec 22  2022 /etc/alternatives/javac -> /usr/lib/jvm/java-21-openjdk-riscv64/bin/javac
user@starfive:/$

Since Gradle is the standard build tool for Java, let's go ahead and install that as well with sudo apt install gradle. This gives us the groovy programming language along with ant. Lets also install Maven with sudo apt install maven as it is a build system also used with Java. And while we're at it, let's go ahead and install kotlin as well with sudo apt install kotlin.

JDBC Install and PostgreSQL JDBC Driver

Since we are using PostgreSQL database engine with PHP and Golang, it makes sense to also install the components needed for a Java program to interact with the same phonebook table that we are accessing with examples in PHP and Golang.

First of all, let's take a look at the existing .jar files available and where they are located:

user@starfive:~/Documents$ find . / -iname "*.jar" 2>/dev/null
/usr/share/java/java-atk-wrapper.jar
/usr/share/java/libintl-0.21.jar
/usr/share/java/libintl.jar
/usr/share/maven-repo/org/gnu/gettext/libintl/debian/libintl-debian.jar
/usr/share/maven-repo/org/gnu/gettext/libintl/0.21/libintl-0.21.jar
/usr/share/ca-certificates-java/ca-certificates-java.jar
/usr/lib/jvm/java-21-openjdk-riscv64/lib/jrt-fs.jar
/usr/lib/jvm/java-17-openjdk-riscv64/lib/jrt-fs.jar
user@starfive:~/Documents$

Next, install the JDBC drivers for PostgreSQL with sudo apt install libpostgresql-jdbc-java and then try it out with a simple HelloWorld.java program which attempts to connect to PostgreSQL.

Here is our simple Java program to access the PostgreSQL database, dbtest, and the phonebook table within it.

Java
import java.sql.*;

class HelloWorld {

    // test making a database connection to the PostgreSQL database
    // see also Stackoverflow post
    //   https://stackoverflow.com/questions/18288058/how-is-driver-class-located-in-jdbc4
    public static void dbtest_test () {
        try {
           // we specify the same PHP PostgreSQL user as we are using
           // with out PHP scripts as it does not need a password.
           // we are also using the same phonebook table from the
           // dbtest database we created with PHP and Golang.
           Connection con = DriverManager.getConnection(
               "jdbc:postgresql://localhost:5432/dbtest","php","");
           //here dbtest is database name, php is username with no password
           Statement stmt=con.createStatement();
           ResultSet rs=stmt.executeQuery("select * from phonebook");
           while(rs.next())
               System.out.println(rs.getString(1) + "  " + rs.getString(2) + " " + rs.getString(3));
           con.close();
        } catch(Exception e) {
             System.out.println(e);
        }
    }

    // main entry point
    public static void main(String[] args) {
        System.out.println("Hello, World!");

        try {
                dbtest_test();
        } catch(Exception e) {
             System.out.println(e);
        }
    }
}

Now we try compiling it and running it.

user@starfive:~/Documents$ javac HelloWorld.java
user@starfive:~/Documents$ java HelloWorld
Hello, World!
java.sql.SQLException: No suitable driver found for jdbc:postgresql://localhost:5432/dbtest
user@starfive:~/Documents$ find . / -iname "*.jar" 2>/dev/null
/usr/share/java/postgresql-jdbc4.jar
/usr/share/java/java-atk-wrapper.jar
/usr/share/java/postgresql.jar
/usr/share/java/libintl-0.21.jar
/usr/share/java/postgresql-jdbc3.jar
/usr/share/java/postgresql-42.5.1.jar
/usr/share/java/libintl.jar
/usr/share/maven-repo/org/gnu/gettext/libintl/debian/libintl-debian.jar
/usr/share/maven-repo/org/gnu/gettext/libintl/0.21/libintl-0.21.jar
/usr/share/maven-repo/org/postgresql/postgresql/42.5.1/postgresql-42.5.1.jar
/usr/share/maven-repo/org/postgresql/postgresql/debian/postgresql-debian.jar
/usr/share/ca-certificates-java/ca-certificates-java.jar
/usr/lib/jvm/java-21-openjdk-riscv64/lib/jrt-fs.jar
/usr/lib/jvm/java-17-openjdk-riscv64/lib/jrt-fs.jar
user@starfive:~/Documents$

Whoops, Java is not finding the PostgreSQL JDBC driver jar file. So let's use the -cp option with the java command. We can see that the package installed the JDBC jar files in the directory /usr/share/java by looking at the results of the find command so let's use a wild card pathname so that Java will pick up whatever it needs per this Stackoverflow post, Including all the jars in a directory within the Java classpath. If we use java -cp "/usr/share/java/*" HelloWorld.java then it works and we see the results from the SQL SELECT statement.

user@starfive:~/Documents/java-projects$ java -cp "/usr/share/java/*" HelloWorld.java
Hello, World!
+1 123 456 7890  John Doe
+101 123 456 7890  Jane Doe
+1 987 456 1234  Ralph Doe
user@starfive:~/Documents/java-projects$

The use of the CLASSPATH environment variable is debated however using it can make some things easier with less typing with simple Java applications. What I did was to add to the /etc/environment file a line to set the CLASSPATH at the time of sign-in using CLASSPATH="/usr/share/java/*". I then logged out and logged back in and checked with the env command. After this, I no longer needed the -cp option for the java command.

Rust install

To install the Rust toolchain on the VisionFive 2 was fairly straightforward. I used the documentation from this article, How to Install Rust Programming Language on Debian 11 through the steps to get a stable version of Rust installed and usable.

  • sudo apt install wget curl build-essential gcc make to ensure those applications are available
  • sudo wget -qO - https://sh.rustup.rs | sudo RUSTUP_HOME=/opt/rust CARGO_HOME=/opt/rust sh -s -- --no-modify-path -y to download rust installer
  • modify /etc/environment adding the needed environment variable, RUSTUP_HOME=/opt/rust
  • rustup default stable to download and set the default rust toolchain
  • sudo echo 'export PATH=$PATH:/opt/rust/bin' | sudo tee -a /etc/profile.d/rust.sh to modify the PATH environment variable to include the rust compiler

I then setup my current terminal session with the following commands:

  • source /etc/environment to set the RUSTUP_HOME environment variable
  • PATH=$PATH:/opt/rust/bin to set the rust compiler into the PATH search

I then tried a simple HelloWorld program in the Rust programming language, using the vi text editor to create a file hello-world.rs with the following content which I compiled with rustc hello-world.rs to generate an executable file hello-world:

Rust
fn main() {
    println!("Hello World, welcome to Rust.");
}

This works so now on to a more complex example, using rust to display what is in our example database.

Rust with PostgreSQL

To continue our pattern of a simple PostgreSQL database query in the programming languages, we are looking at, let's take a look at an example in rust. What we quickly find is that rust has an infrastructure with quite a bit of plumbing and you need to understand the perspective and work within that world view.

The first thing is to find an example and I started with this one, Working with Postgres. One thing that I have found is that it appears most things are done with the cargo command followed by various arguments. See Why do I get "can't find crate" that is listed as a dependency in Cargo.toml when I compile with rustc?. So even though in our hello-world.rs example above we compiled directly with rustc, that's not really the way to do it for anything more complicated.

First, let's create our rust project with cargo new rust-postgresql. Then cd into the new folder rust-postgresql that was created. You will see a subdirectory, src, and a file, Cargo.toml. Inside the subdirectory src is a file, main.rs, which is a simple hello world application that we will replace.

Next, we need to install the PostgreSQL rust crate with cargo add postgres. The cargo command will set up various bits including updating the Cargo.toml file and create an additional file, Cargo.lock.

Next we put into our src subdirectory a replacement for the placeholder main.rs file created by the cargo new with our main.rs source file that reads from the PostgreSQL database.

Rust
use postgres::{Client, Error, NoTls};

fn main() -> Result<(), Error> {
    let mut client = Client::connect("postgresql://php:@localhost/dbtest", NoTls)?;

    for row in client.query("SELECT * FROM phonebook", &[])? {
        let phonenumber: &str = row.get(0);
        let firstname: &str = row.get(1);
        let lastname: &str = row.get(2);
        println!(
            " {} | {} | {}",
            phonenumber, firstname, lastname
        );
    }
    Ok(())
}

Then we compile our program with cargo build. The executable appears in a subdirectory to our project folder at the same level as the src subdirectory, ./target/debug.

Using the Code

The above programming language examples all do a simple query of a PostgreSQL database table and print the results.

A Test of PHP with PostgreSQL

The easiest way for an initial test that PHP and the PostgreSQL engine are talking with each other is to create a simple PHP script that you can run from the command line to create a table, insert a row into the table, and then read it back out and print it.

Before running this PHP script, you will need to have a valid user/role and a created database. Both can be created using the psql utility before trying to run the script below. This Stackoverflow post describes the error handling of PHP, What happens with set_error_handler() on PHP7 now that all errors are exceptions?.

PHP
#!/usr/bin/php
<?php

// Must install postgresql drivers for php.
//   sudo apt-get install php-pgsql

function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}

set_error_handler("exception_error_handler");

try {
    $db = pg_connect("user=php dbname=dbtest");
    $result1 = pg_query($db, "CREATE TABLE phonebook(phone VARCHAR(32), firstname VARCHAR(32), lastname VARCHAR(32), address VARCHAR(64));");
    $result1 = pg_query($db, "INSERT INTO phonebook(phone, firstname, lastname, address) VALUES('+1 123 456 7890', 'John', 'Doe', 'North America')");
    $result1 = pg_query($db, "SELECT * FROM phonebook");
    while($data = pg_fetch_array($result1, NULL, PGSQL_ASSOC)) {
        print  $data["firstname"] . " " .  $data["lastname"] . "\n";
    }
} catch (Exception $e) {
        echo $e->getMessage();
}

?>

Once you have the above file, you can then use chmod +x [filename] to make it executable from the bash command line. At that point, you can run the PHP script and see what happens. If you want to run it multiple times, you can add an additional pg_query call to perform a DROP TABLE phonebook; SQL statement as in $result1 = pg_query($db, "DROP TABLE phonebook;"); before the statement with the CREATE TABLE.

If the user/role is incorrect, you will see an error something like:

pg_connect(): Unable to connect to PostgreSQL server: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  Peer authentication failed for user "xuser"

Or a problem with the database name, you will see something like:

pg_connect(): Unable to connect to PostgreSQL server: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  database "dbtestx" does not exist

Or a problem with the return result, you will see something like:

PHP Parse error:  syntax error, unexpected variable "$result1" in /home/user/Documents/github/web/phpdb/displaydb.php on line 28

The Mosquitto Example Program

In order to compile the Mosquitto client test program, you will need to have the GNU C compiler installed. The command line to compile and link the example has to specify the additional libraries needed for the Mosquitto communications, the parsing of the JSON text messages, and the persistent data store:

BAT
cc -o mqtttest mqtttest.c -lmosquitto -lfastjson -lsqlite3

The program is short and simple with four different options. If you run the program without any arguments, it will print a short synopsis of the arguments.

user@starfive:~/Documents/github/raspberrypi/mqtt$ ./mqtttest
mqtttest [-ps msgqueue] [-h hostname]
    -p msgqueue    -> publish messages to message queue msgqueue
    -s msgqueue    -> subscribe to message queue msgqueue
    -h hostname    -> publish or subscribe to broker on hostname
    -d             -> dump the SQLite database to standard output
user@starfive:~/Documents/github/raspberrypi/mqtt$

The easiest way to use this example program is to open up two terminal windows and after compiling the example program in one of the windows to then run ./mqtttest -s "topic/test" to start the subscriber and then in the other window to run ./mqtttest -p "topic/test" to start the publisher. You will then see a series of received messages printed out by the subscriber to the topic, as the publisher sends a series of messages. The subscriber logs each of the messages into an SQLite3 database. The subscriber will continue to wait for new messages until it is killed with a control-C in that terminal window.

The contents of the SQLite3 database created by the subscriber can be dumped to standard output using ./mqtttest -d. Since the output is to standard out, it can be redirected to a file if you desire.

Points of Interest

The first point and in some ways the most fundamental is how free I've felt during this exploration of software for the VisionFive 2 SBC to make mistakes. There is something about the size of the device and how easy it is to just pop the microSD card out and put a new image on the card to start over that made experimentation easier.

Writing this article ended up being a whirlwind tour through a number of programming languages. I've been wanting to learn Rust so this was an opportunity to at least dip my toes into that pool. For me as a C/C++ programmer, Rust has a complex syntax. It feels a bit different than Go or Java. However, C++ has become more complex since C++11 and the latest standard changes have resulted in a much more different language than pre-C++11. Functional programming is leaching into more and more of the most common programming languages.

It amazed me how much obsolete, wrong, incomplete, or otherwise unusable information is served up from an internet search. And I really did not appreciate having to wade through still another Docker setup description in order to get to what I really needed.

The software that I've worked with during the writing of this article seems pretty reliable and robust on the VisionFive 2. I was at first concerned that I would run into problems when I saw "unstable" as packages installed. I'd say that 99% of the problems I ran into were due to my own mistakes and ignorance. I think this actually underscores a crucial keystone to software: software that works reliably and robustly on other platforms and architectures tends to work just as well on new architectures so long as the toolchain used to build them generates reliable and robust executables and the underlying firmware and operating system stack is reliable and robust.

History

  • 16th December, 2023: Initial version of the article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Retired Georgia Southern University
United States United States
Team lead for a point of sale software application written in C and C++. Previous experience with Nortel Networks on software for telecommunications products as well as Program Management.

Education:
BS Computer Science
MBA
Masters in Project Management

Comments and Discussions

 
-- There are no messages in this forum --