Skip to content

Sort sequence incorrect when User Defined Function changes column display format. #2149

@rjmoses

Description

@rjmoses

Details for the issue
I created a sqlite User Defined Function (extension) called "shortTime" that takes a Unix time_t as input and formats it into "MM/DD/YY HH:MM" display format. When selecting the sort sequence on the column, it is sorted by the text mm/dd/yy.... rather than the underlying time_t value.

(The standard sqlite function, strftime, does not support a short year (%y)).

What did you do?

For testing purposes, I created a table of id, FileName, Suffix, Date Accessed where Date Accessed began January 1, 2010 and incremented one day per file name.

What did you expect to see?

When clicking on the Date Accessed column, I expect to see the file names, etc., sorted in the sequence of lowest mm/dd/yy to highest mm/dd/yy in date sequence. Specifically:

(mm/dd/yy)
01/01/10
01/02/10
01/03/10
.....
12/31/10
01/01/11
01/02/11
....
12/31/11
01/01/12
...
12/31/12

What did you see instead?

(mm/dd/yy)
01/01/10
01/01/11
01/01/12
....
01/01/17 (last year date for test case
01/02/10
01/02/11
01/02/12
....
01/02/17
01/03/10
01/03/11
...

Useful extra information

  1. Analyzed generated SQL statements.
    sqlitebrowser SQL statement:
    SELECT "rowid","id","FileName","Suffix",shortTime("Accessed") AS "Accessed" FROM "main"."FileList" ORDER BY "Accessed" ASC LIMIT 0, 49999;

  2. Ran an SQL statement where the AS field name was changed:
    SELECT "rowid","id","FileName","Suffix",shortTime("Accessed") AS "Accessed1" FROM "main"."FileList" ORDER BY "Accessed" ASC LIMIT 0, 49999;

The sort sequence appears to work correctly using this SQL statement for both ASC and DESC, where the AS name was change. (It changes the column name also.)

  1. Changing the shortTime function to create a field in the format "yy/mm/dd" give the expected results when sorting.

  2. As a SWAG, this appears to be a problem with using -- SELECT function("fieldName") AS "fieldName" ORDER BY "fieldName"-- in that sqlite uses "fieldName" after the function is executed but before the ORDER BY sort.


The info below often helps, please fill it out if you're able to. :)

What operating system are you using?

  • Linux: ( Linux Mint 19.2)

What is your DB4S version?

  • Other: 3.11.99
    Built from source code using Qt 5.14.1
    Sqlite version 3.22.0

Did you also

BTW: sqlitebrowser is a superb utility and well written. Thank you.

Extension code:
(Must be compiled with -DEXTSHAREDLIB_LIBRARY)

-----------------------------------Header File:--------------------------------------

#ifndef HEADER_H
#define HEADER_H

#include <QtCore/QtGlobal>

#if defined(EXTSHAREDLIB_LIBRARY)
#  define EXTSHAREDLIB_EXPORT Q_DECL_EXPORT
#else
#  define EXTSHAREDLIB_EXPORT Q_DECL_IMPORT
#endif

#endif // HEADER_H

-----------------------------------Function File:--------------------------------------

#include <sqlite3ext.h>

SQLITE_EXTENSION_INIT1

#include <stdio.h>
#include <QtCore/QtGlobal>
#include <QFileInfo>
#include <QDateTime>
#include <string.h>
#include "Extensions.h"

extern "C" EXTSHAREDLIB_EXPORT void shortTime(sqlite3_context* ctx, int num_arguments, sqlite3_value* arguments[])
{
    static char timestr[50];

    if (num_arguments != 1) {
        sqlite3_result_error(ctx, QString("Invalid number of arguments for shortTime call.").toUtf8(), -1);
        return;
    }

    time_t sqltime = (sqlite3_value_int(arguments[0]));
    struct tm * timeinfo;
    timeinfo = localtime(&sqltime);
    strftime(timestr, sizeof(timestr), "%y/%m/%d %H:%M", timeinfo);

    char* output_str = new char[strlen(timestr)+1];
    strcpy(output_str, timestr);

    sqlite3_result_text(ctx, output_str, static_cast<int>(strlen(output_str)), [](void* ptr) {
        char* cptr = static_cast<char*>(ptr);
        delete cptr;
    });
}

extern "C" EXTSHAREDLIB_EXPORT int sqlite3_extensions_init( sqlite3 *db, char **pzErrMsg,  const sqlite3_api_routines *pApi)
{
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi)
  (void)pzErrMsg;  /* Unused parameter */
  rc = sqlite3_create_function(db, "shortTime", 1,
                    SQLITE_UTF8,
                    nullptr, shortTime, nullptr, nullptr);
  return rc;
}

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions