ISQL - Internet SQL embedded database  (SDK drop, 64-bit / x64)
==============================================================

Copyright (c) 2026 Muhammad Anisur Rahman.  MIT License - see LICENSE.

An embedded relational + storage-vector SQL engine that runs in-process in your
C application. No server and no network are required. This is the 64-bit (x64)
build: record numbers and file offsets are genuine 64-bit values.

The database directory db\ ships EMPTY. The engine creates the catalog and
system tables on the first connection, so just point it at a home directory
that contains an empty db\ sub-folder.


INSTALL
-------
    install.bat                     prompts for a home directory (default C:\ISQL)
    install.bat D:\MyIsql           install to a specific directory
    install.bat D:\MyIsql /nopath   install without touching PATH
    install.bat D:\MyIsql /system   register on the SYSTEM PATH (needs admin)

By default <home>\bin is added to your PER-USER PATH; no administrator rights
are needed. Open a new command prompt afterwards for it to take effect.
uninstall.bat removes that PATH entry again and leaves your data alone.


QUICK START
-----------
0. Nothing to build - bin\ ships working programs (new in 1.24; 1.23
   made you build a shell before you could see anything at all):

       bin\isqlsh.exe -dbhome C:\ISQL
       iSql> help;

   Or run a file of statements and exit:

       bin\isqlsh.exe -q -e -dbhome C:\ISQL -cmd schema.sql

   -dbhome, -ip, -port, -u, -pwd, -cmd and -version mean the same thing in
   every program in bin\. doc\isql-help-version.txt is the full reference and
   also lists every SQL command.

1. Self-checking example (exercises the SQL command set):
       examples\build_example.bat
       examples\isql_example.exe  C:\ISQL

2. Build your own shell from the example source:
       examples\build_shell.bat
       bin\isql_shell.exe  C:\ISQL
       isql> help;

The build scripts locate the MSVC x64 tools automatically (via vswhere, then
common install paths), so they are not tied to one Visual Studio version. If
detection fails, set VCVARS to your vcvars64.bat and re-run.

Keep isqldll.dll next to your .exe, or on PATH. This matters more than it
looks: the DLL is a LOAD-TIME import, so without it an executable can exit
silently with no error at all.


LAYOUT
------
  db\        your database (created empty; the engine fills it)
  bin\       isqldll.dll plus seven ready-built programs:
               isqlsh.exe        scriptable shell, embedded or remote
               shell.exe         local shell, loads isqldll.dll
               shelldev.exe      the same, developer build
               locshell.exe      local shell, statically linked
               shellonlib.exe    the same, second variant
               isqlserverd.exe   headless server
               isqlserver.exe    windowed server
             (isql_shell.exe appears here too once you run build_shell.bat)
  lib\       isqldll.lib (DLL import), isqllib.lib (static)
  include\h\ isql.h  <-- include THIS one; it pulls in the rest
             isqlversion.h, isqlopts.h, isqlcfg.h - the version string and the
             shared command-line/config handling, if you want your own program
             to take the same flags as the shipped ones
  include\   newpwd.*, vlr.h, vlrengine.h
  examples\  isql_example.c, isql_shell.c, build_*.bat, findvc.bat
  doc\       HOWTO_BUILD_C_APP.md          <-- full guide, start here
             isql-help-version.txt         every SQL command and option
             SERVER_AND_SHELL.md           isqlsh and isqlserverd manual
             RELEASE_NOTES_1.25.md   <-- GROUP BY was broken before 1.25;
                                         read this if you use grouped totals
             RELEASE_NOTES_1.24.md, RELEASE_NOTES_1.23.md
             VLR_ARCHITECTURE.txt, VLR_API.txt
  isql.cfg   engine configuration (see the note inside it)


ACCESS
------
Embedded owner access:   ISQL_SetOwnerAccess(obj)   - the path the example and
                         shell use, and the one to start from.
Multi-user login:        add user <n>,<pwd>,<a|m|o>;  then  login <n>,<pwd>;
                         ISQL supports server and standalone modes, four
                         privilege tiers and five lock levels.

Passwords are SHA-256 (newpwd); legacy PC1 hashes migrate on first successful
login.


VARIABLE-LENGTH RECORDS (VLR) - DESIGNED, NOT YET IMPLEMENTED
------------------------------------------------------------
    *** The engine in this drop does NOT accept the VLR syntax. ***

The intent is that a table may store variable-length rows instead of
fixed-width padded ones, saving substantial disk on columns that are mostly
short. What the shipped engine actually does with the documented syntax:

    create table t (id number(5), name char(20)) (recordformat=vlr);
        ERROR: Unexpected symbol: '(' around column '46'

The parser has no `recordformat` clause, so nothing reaches a VLR code path.
Earlier drops of this README described the feature as though it worked; it
never has. Every table you create is fixed-width, which is also why nothing in
your database can be affected by this.

doc\VLR_ARCHITECTURE.txt and doc\VLR_API.txt remain in the drop because the
on-disk format and API they describe are the design being worked towards.
Read them as a specification, not as a description of this build.


COMPATIBILITY NOTES - READ BEFORE WRITING CODE AGAINST ISQL
-----------------------------------------------------------
Six behaviours that differ from other SQL engines. All are by design; the
messages the engine returns do not always make clear which one you have hit.
Each is stated with the reason, so you can tell it apart from a real error.

1. FIELD NAMES ARE LIMITED TO 10 CHARACTERS (classic tables).
   This is why a column named "description" is rejected: it is 11 characters.
   It is NOT a reserved-word conflict - it is one character too long, so
   renaming to any other 11-character name fails the same way. Either use a
   name of 10 characters or fewer ("descr", "notes"), or switch the table to
   EXTENDED mode, where field names may be up to 218 characters:

       ISQL_SetExtendedTableMode(slot);     /* before CREATE TABLE */
       ISQL_ClearExtendedTableMode(slot);

2. TEXT FIELDS ARE LIMITED TO 255 CHARACTERS.
   A wide fixed-width field is the wrong tool for large values. For anything
   bigger, use the field type meant for it:

       BLOB    - large variable-length values
       BINARY  - raw binary payloads
       FILE    - file-backed content
       DIR     - directory-backed content

   Declaring a text field wider than 255 fails at schema creation; pick the
   matching field type instead rather than widening the text field.

3. COLUMN NAMES COME BACK UPPERCASE.
   Field names are upper-cased by the engine, so a column created as
   "cust_name" is returned as "CUST_NAME". Compare column names
   case-insensitively, or upper-case your own literals before matching. This
   affects result-set metadata, not the stored data.

4. FIXED-WIDTH TEXT RESULTS ARE SPACE-PADDED.
   A fixed-width text column is stored padded to its declared width, and the
   value you read back carries that padding. Trim trailing spaces on read if
   you need the original string. This is ordinary CHAR semantics, not a bug -
   but it does mean strcmp() against an unpadded literal will not match.

5. DROP INDEX IS REVERSIBLE - IT DOES NOT FREE THE NAME. USE DELETE INDEX.
   This is the one that surprises people. ISQL has a three-command index
   lifecycle, and DROP is the *recoverable* one:

       DROP INDEX <name>;          mark dropped, KEEP the file  (reversible)
       RECOVER INDEX <name>;       bring a dropped index back
       DELETE INDEX <name>;        remove permanently, FREE the name

   So after DROP INDEX, re-creating an index of the same name is refused with
       "Entry 'index\<name>' already exists in the disk. Select another name."
   That is not a failed drop - the drop succeeded, and the entry is deliberately
   retained so RECOVER INDEX can restore it. If you want the name back, use
   DELETE INDEX. If you want the index back, use RECOVER INDEX.

   Both spellings of DROP are accepted and do exactly the same thing:

       DROP INDEX <name>;                  /* ISQL form          */
       DROP INDEX <name> ON <table>;       /* standard SQL form  */

   (The "ON <table>" clause used to be rejected by the end-of-command check.
   It is now parsed and ignored, since an ISQL index name is already unique
   across the database.)

   Dropping a table removes its indexes with it, which is why DROP TABLE on an
   indexed table has always worked.

6. DO NOT CALL ISQL_DeleteInstance AFTER ISQL_StopInternetSql.
   ISQL_StopInternetSql() ignores the startid you pass and performs a GLOBAL
   engine shutdown. Per-instance teardown afterwards operates on state that has
   already been torn down. The correct shutdown is simply:

       ISQL_StopInternetSql(startid);       /* and stop there */

   The example programs in this SDK do exactly that, and deliberately do not
   call ISQL_DeleteInstance. Call ISQL_DeleteInstance only to discard an
   instance you created but never started.

7. FIXED IN THIS DROP: ISQL_DeleteInstance crashed on x64.
   Where you did use ISQL_DeleteInstance to tear down an instance you had
   started, it faulted on 64-bit builds: internally the slot pointer was cast
   to a 32-bit long before being handed to the engine's shutdown routine, so
   the engine dereferenced an address with its top half missing.

   It was easy to misread. The fault happened AFTER all the SQL work had been
   committed, so the data on disk was correct and the process simply died on
   the way out - it looked like a random exit rather than a teardown bug.

   Both teardown paths now behave: ISQL_StopInternetSql(startid) as described
   in note 6, and ISQL_DeleteInstance on a started instance.


KNOWN LIMITATIONS (stated deliberately)
---------------------------------------
- Run Apache in PREFORK mode for the CGI/PHP paths. The engine's thread-safety
  refactor is not complete, so do not assume a threaded MPM is safe.
- The ODBC driver is not part of this release; the ODBC example is reference
  code for once it ships.
- The JNI shim must be built to match your JVM's bitness.

See doc\HOWTO_BUILD_C_APP.md for the complete API and build instructions.
