@@ -2588,7 +2588,8 @@ enum Vec0RescoreQuantizerType {
25882588
25892589struct Vec0RescoreConfig {
25902590 enum Vec0RescoreQuantizerType quantizer_type ;
2591- int oversample ;
2591+ int oversample ; // CREATE-time default
2592+ int oversample_search ; // runtime override (0 = use default)
25922593};
25932594#endif
25942595
@@ -3399,8 +3400,9 @@ static sqlite3_module vec_eachModule = {
33993400
34003401#define VEC0_COLUMN_ID 0
34013402#define VEC0_COLUMN_USERN_START 1
3402- #define VEC0_COLUMN_OFFSET_DISTANCE 1
3403- #define VEC0_COLUMN_OFFSET_K 2
3403+ #define VEC0_COLUMN_OFFSET_COMMAND 1
3404+ #define VEC0_COLUMN_OFFSET_DISTANCE 2
3405+ #define VEC0_COLUMN_OFFSET_K 3
34043406
34053407#define VEC0_SHADOW_INFO_NAME "\"%w\".\"%w_info\""
34063408
@@ -3498,6 +3500,10 @@ struct vec0_vtab {
34983500 // Will change the schema of the _rowids table, and insert/query logic.
34993501 int pkIsText ;
35003502
3503+ // True if the hidden command column (named after the table) exists.
3504+ // Tables created before v0.1.10 or without _info table don't have it.
3505+ int hasCommandColumn ;
3506+
35013507 // number of defined vector columns.
35023508 int numVectorColumns ;
35033509
@@ -3777,20 +3783,19 @@ int vec0_num_defined_user_columns(vec0_vtab *p) {
37773783 * @param p vec0 table
37783784 * @return int
37793785 */
3786+ int vec0_column_command_idx (vec0_vtab * p ) {
3787+ // Command column is the first hidden column (right after user columns)
3788+ return VEC0_COLUMN_USERN_START + vec0_num_defined_user_columns (p );
3789+ }
3790+
37803791int vec0_column_distance_idx (vec0_vtab * p ) {
3781- return VEC0_COLUMN_USERN_START + ( vec0_num_defined_user_columns (p ) - 1 ) +
3782- VEC0_COLUMN_OFFSET_DISTANCE ;
3792+ int base = VEC0_COLUMN_USERN_START + vec0_num_defined_user_columns (p );
3793+ return base + ( p -> hasCommandColumn ? 1 : 0 ) ;
37833794}
37843795
3785- /**
3786- * @brief Returns the index of the k hidden column for the given vec0 table.
3787- *
3788- * @param p vec0 table
3789- * @return int k column index
3790- */
37913796int vec0_column_k_idx (vec0_vtab * p ) {
3792- return VEC0_COLUMN_USERN_START + ( vec0_num_defined_user_columns (p ) - 1 ) +
3793- VEC0_COLUMN_OFFSET_K ;
3797+ int base = VEC0_COLUMN_USERN_START + vec0_num_defined_user_columns (p );
3798+ return base + ( p -> hasCommandColumn ? 2 : 1 ) ;
37943799}
37953800
37963801/**
@@ -5205,6 +5210,74 @@ static int vec0_init(sqlite3 *db, void *pAux, int argc, const char *const *argv,
52055210 }
52065211 }
52075212
5213+ // Determine whether to add the FTS5-style hidden command column.
5214+ // New tables (isCreate) always get it; existing tables only if created
5215+ // with v0.1.10+ (which validated no column name == table name).
5216+ int hasCommandColumn = 0 ;
5217+ if (isCreate ) {
5218+ // Validate no user column name conflicts with the table name
5219+ const char * tblName = argv [2 ];
5220+ int tblNameLen = (int )strlen (tblName );
5221+ for (int i = 0 ; i < numVectorColumns ; i ++ ) {
5222+ if (pNew -> vector_columns [i ].name_length == tblNameLen &&
5223+ sqlite3_strnicmp (pNew -> vector_columns [i ].name , tblName , tblNameLen ) == 0 ) {
5224+ * pzErr = sqlite3_mprintf (
5225+ VEC_CONSTRUCTOR_ERROR
5226+ "column name '%s' conflicts with table name (reserved for command column)" ,
5227+ tblName );
5228+ goto error ;
5229+ }
5230+ }
5231+ for (int i = 0 ; i < numPartitionColumns ; i ++ ) {
5232+ if (pNew -> paritition_columns [i ].name_length == tblNameLen &&
5233+ sqlite3_strnicmp (pNew -> paritition_columns [i ].name , tblName , tblNameLen ) == 0 ) {
5234+ * pzErr = sqlite3_mprintf (
5235+ VEC_CONSTRUCTOR_ERROR
5236+ "column name '%s' conflicts with table name (reserved for command column)" ,
5237+ tblName );
5238+ goto error ;
5239+ }
5240+ }
5241+ for (int i = 0 ; i < numAuxiliaryColumns ; i ++ ) {
5242+ if (pNew -> auxiliary_columns [i ].name_length == tblNameLen &&
5243+ sqlite3_strnicmp (pNew -> auxiliary_columns [i ].name , tblName , tblNameLen ) == 0 ) {
5244+ * pzErr = sqlite3_mprintf (
5245+ VEC_CONSTRUCTOR_ERROR
5246+ "column name '%s' conflicts with table name (reserved for command column)" ,
5247+ tblName );
5248+ goto error ;
5249+ }
5250+ }
5251+ for (int i = 0 ; i < numMetadataColumns ; i ++ ) {
5252+ if (pNew -> metadata_columns [i ].name_length == tblNameLen &&
5253+ sqlite3_strnicmp (pNew -> metadata_columns [i ].name , tblName , tblNameLen ) == 0 ) {
5254+ * pzErr = sqlite3_mprintf (
5255+ VEC_CONSTRUCTOR_ERROR
5256+ "column name '%s' conflicts with table name (reserved for command column)" ,
5257+ tblName );
5258+ goto error ;
5259+ }
5260+ }
5261+ hasCommandColumn = 1 ;
5262+ } else {
5263+ // xConnect: check _info shadow table for version
5264+ sqlite3_stmt * stmtInfo = NULL ;
5265+ char * zInfoSql = sqlite3_mprintf (
5266+ "SELECT value FROM " VEC0_SHADOW_INFO_NAME " WHERE key = 'CREATE_VERSION_PATCH'" ,
5267+ argv [1 ], argv [2 ]);
5268+ if (zInfoSql ) {
5269+ int infoRc = sqlite3_prepare_v2 (db , zInfoSql , -1 , & stmtInfo , NULL );
5270+ sqlite3_free (zInfoSql );
5271+ if (infoRc == SQLITE_OK && sqlite3_step (stmtInfo ) == SQLITE_ROW ) {
5272+ int patch = sqlite3_column_int (stmtInfo , 0 );
5273+ hasCommandColumn = (patch >= 10 ); // v0.1.10+
5274+ }
5275+ // If _info doesn't exist or has no version, assume old table
5276+ sqlite3_finalize (stmtInfo );
5277+ }
5278+ }
5279+ pNew -> hasCommandColumn = hasCommandColumn ;
5280+
52085281 sqlite3_str * createStr = sqlite3_str_new (NULL );
52095282 sqlite3_str_appendall (createStr , "CREATE TABLE x(" );
52105283 if (pkColumnName ) {
@@ -5246,7 +5319,11 @@ static int vec0_init(sqlite3 *db, void *pAux, int argc, const char *const *argv,
52465319 }
52475320
52485321 }
5249- sqlite3_str_appendall (createStr , " distance hidden, k hidden) " );
5322+ if (hasCommandColumn ) {
5323+ sqlite3_str_appendf (createStr , " \"%w\" hidden, distance hidden, k hidden) " , argv [2 ]);
5324+ } else {
5325+ sqlite3_str_appendall (createStr , " distance hidden, k hidden) " );
5326+ }
52505327 if (pkColumnName ) {
52515328 sqlite3_str_appendall (createStr , "without rowid " );
52525329 }
@@ -10161,25 +10238,31 @@ static int vec0Update(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv,
1016110238 }
1016210239 // INSERT operation
1016310240 else if (argc > 1 && sqlite3_value_type (argv [0 ]) == SQLITE_NULL ) {
10164- #if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE || SQLITE_VEC_ENABLE_DISKANN
10165- // Check for command inserts: INSERT INTO t(rowid) VALUES ('command-string')
10166- // The id column holds the command string.
10167- sqlite3_value * idVal = argv [2 + VEC0_COLUMN_ID ];
10168- if (sqlite3_value_type (idVal ) == SQLITE_TEXT ) {
10169- const char * cmd = (const char * )sqlite3_value_text (idVal );
10170- vec0_vtab * p = (vec0_vtab * )pVTab ;
10171- int cmdRc = SQLITE_EMPTY ;
10241+ vec0_vtab * p = (vec0_vtab * )pVTab ;
10242+ // FTS5-style command dispatch via hidden column named after table
10243+ if (p -> hasCommandColumn ) {
10244+ sqlite3_value * cmdVal = argv [2 + vec0_column_command_idx (p )];
10245+ if (sqlite3_value_type (cmdVal ) == SQLITE_TEXT ) {
10246+ const char * cmd = (const char * )sqlite3_value_text (cmdVal );
10247+ int cmdRc = SQLITE_EMPTY ;
10248+ #if SQLITE_VEC_ENABLE_RESCORE
10249+ cmdRc = rescore_handle_command (p , cmd );
10250+ #endif
1017210251#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE
10173- cmdRc = ivf_handle_command (p , cmd , argc , argv );
10252+ if (cmdRc == SQLITE_EMPTY )
10253+ cmdRc = ivf_handle_command (p , cmd , argc , argv );
1017410254#endif
1017510255#if SQLITE_VEC_ENABLE_DISKANN
10176- if (cmdRc == SQLITE_EMPTY )
10177- cmdRc = diskann_handle_command (p , cmd );
10256+ if (cmdRc == SQLITE_EMPTY )
10257+ cmdRc = diskann_handle_command (p , cmd );
1017810258#endif
10179- if (cmdRc != SQLITE_EMPTY ) return cmdRc ; // handled (or error)
10180- // SQLITE_EMPTY means not a recognized command — fall through to normal insert
10259+ if (cmdRc == SQLITE_EMPTY ) {
10260+ vtab_set_error (pVTab , "unknown vec0 command: '%s'" , cmd );
10261+ return SQLITE_ERROR ;
10262+ }
10263+ return cmdRc ;
10264+ }
1018110265 }
10182- #endif
1018310266 return vec0Update_Insert (pVTab , argc , argv , pRowid );
1018410267 }
1018510268 // UPDATE operation
0 commit comments